Rust 结构体与枚举详解
概述
结构体(Struct)和枚举(Enum)是 Rust 中创建自定义类型的主要方式。它们允许你将相关数据组合在一起,并提供类型安全保证。
结构体
定义结构体
struct User {
username: String,
email: String,
sign_in_count: u64,
active: bool,
}
创建结构体实例
fn main() {
let user1 = User {
email: String::from("someone@example.com"),
username: String::from("someusername123"),
active: true,
sign_in_count: 1,
};
println!("用户: {}", user1.username);
println!("邮箱: {}", user1.email);
}
访问结构体字段
struct User {
username: String,
email: String,
sign_in_count: u64,
active: bool,
}
fn main() {
let user1 = User {
email: String::from("someone@example.com"),
username: String::from("someusername123"),
active: true,
sign_in_count: 1,
};
// 访问字段
println!("用户名: {}", user1.username);
println!("邮箱: {}", user1.email);
println!("登录次数: {}", user1.sign_in_count);
println!("是否活跃: {}", user1.active);
}
结构体更新语法
struct User {
username: String,
email: String,
sign_in_count: u64,
active: bool,
}
fn main() {
let user1 = User {
email: String::from("someone@example.com"),
username: String::from("someusername123"),
active: true,
sign_in_count: 1,
};
let user2 = User {
email: String::from("another@example.com"),
username: String::from("anotherusername567"),
..user1 // 使用 user1 的其他字段
};
println!("用户2: {}", user2.username);
}
元组结构体
struct Color(i32, i32, i32);
struct Point(i32, i32);
fn main() {
let black = Color(0, 0, 0);
let origin = Point(0, 0);
println!("颜色: {} {} {}", black.0, black.1, black.2);
println!("点: {} {}", origin.0, origin.1);
}
类单元结构体
struct AlwaysEqual;
fn main() {
let subject = AlwaysEqual;
// 可以实例化,但没有实际数据
}
结构体数据的所有权
struct User {
username: String, // 拥有 String 数据
email: String,
sign_in_count: u64,
active: bool,
}
fn main() {
let user1 = User {
email: String::from("someone@example.com"),
username: String::from("someusername123"),
active: true,
sign_in_count: 1,
};
let user2 = user1; // user1 的所有权移动到 user2
// println!("{}", user1.username); // 错误!user1 已经失效
println!("{}", user2.username);
}
使用引用避免所有权转移
struct User {
username: &str, // 使用字符串切片
email: &str,
sign_in_count: u64,
active: bool,
}
fn main() {
let username = String::from("someusername123");
let email = String::from("someone@example.com");
let user1 = User {
email: &email,
username: &username,
active: true,
sign_in_count: 1,
};
println!("用户: {}", user1.username);
}
方法
定义方法
struct Rectangle {
width: u32,
height: u32,
}
impl Rectangle {
// 方法
fn area(&self) -> u32 {
self.width * self.height
}
}
fn main() {
let rect1 = Rectangle {
width: 30,
height: 50,
};
println!("矩形的面积是 {} 平方像素", rect1.area());
}
带有更多参数的方法
struct Rectangle {
width: u32,
height: u32,
}
impl Rectangle {
fn area(&self) -> u32 {
self.width * self.height
}
fn can_hold(&self, other: &Rectangle) -> bool {
self.width > other.width && self.height > other.height
}
}
fn main() {
let rect1 = Rectangle {
width: 30,
height: 50,
};
let rect2 = Rectangle {
width: 10,
height: 40,
};
let rect3 = Rectangle {
width: 60,
height: 45,
};
println!("rect1 能容纳 rect2 吗? {}", rect1.can_hold(&rect2));
println!("rect1 能容纳 rect3 吗? {}", rect1.can_hold(&rect3));
}
关联函数
struct Rectangle {
width: u32,
height: u32,
}
impl Rectangle {
fn square(size: u32) -> Rectangle {
Rectangle {
width: size,
height: size,
}
}
}
fn main() {
let sq = Rectangle::square(3);
println!("正方形: {} x {}", sq.width, sq.height);
}
多个 impl 块
struct Rectangle {
width: u32,
height: u32,
}
impl Rectangle {
fn area(&self) -> u32 {
self.width * self.height
}
}
impl Rectangle {
fn can_hold(&self, other: &Rectangle) -> bool {
self.width > other.width && self.height > other.height
}
}
fn main() {
let rect1 = Rectangle {
width: 30,
height: 50,
};
println!("面积: {}", rect1.area());
}
枚举
定义枚举
enum IpAddr {
V4(String),
V6(String),
}
fn main() {
let home = IpAddr::V4(String::from("127.0.0.1"));
let loopback = IpAddr::V6(String::from("::1"));
}
枚举变体中的数据
enum IpAddr {
V4(u8, u8, u8, u8),
V6(String),
}
fn main() {
let home = IpAddr::V4(127, 0, 0, 1);
let loopback = IpAddr::V6(String::from("::1"));
}
枚举方法
enum Message {
Quit,
Move { x: i32, y: i32 },
Write(String),
ChangeColor(i32, i32, i32),
}
impl Message {
fn call(&self) {
// 在这里定义方法体
}
}
fn main() {
let m = Message::Write(String::from("hello"));
m.call();
}
Option 枚举
Option 是标准库中定义的枚举,用于表示可能存在或不存在的值:
enum Option<T> {
Some(T),
None,
}
使用示例:
fn main() {
let some_number = Some(5);
let some_string = Some("a string");
let absent_number: Option<i32> = None;
println!("some_number: {:?}", some_number);
println!("some_string: {:?}", some_string);
println!("absent_number: {:?}", absent_number);
}
Option 与模式匹配:
fn main() {
let some_number = Some(5);
match some_number {
Some(i) => println!("值是: {}", i),
None => println!("没有值"),
}
}
Option 的优势
fn main() {
// 有 Option
let x: Option<i8> = Some(5);
let y: Option<i8> = Some(6);
// 错误!不能直接相加
// let sum = x + y;
// 需要处理 None 的情况
let sum = match x {
Some(i) => match y {
Some(j) => Some(i + j),
None => None,
},
None => None,
};
println!("和: {:?}", sum);
}
match 控制流
基本 match
enum Coin {
Penny,
Nickel,
Dime,
Quarter,
}
fn value_in_cents(coin: Coin) -> u8 {
match coin {
Coin::Penny => 1,
Coin::Nickel => 5,
Coin::Dime => 10,
Coin::Quarter => 25,
}
}
fn main() {
let coin = Coin::Penny;
println!("硬币价值: {} 分", value_in_cents(coin));
}
绑定值
enum UsState {
Alabama,
Alaska,
// 等等...
}
enum Coin {
Penny,
Nickel,
Dime,
Quarter(UsState), // 包含 UsState 值
}
fn value_in_cents(coin: Coin) -> u8 {
match coin {
Coin::Penny => 1,
Coin::Nickel => 5,
Coin::Dime => 10,
Coin::Quarter(state) => {
println!("州 quarter 来自 {:?}", state);
25
}
}
}
fn main() {
let coin = Coin::Quarter(UsState::Alaska);
println!("硬币价值: {} 分", value_in_cents(coin));
}
匹配 Option
fn plus_one(x: Option<i32>) -> Option<i32> {
match x {
None => None,
Some(i) => Some(i + 1),
}
}
fn main() {
let five = Some(5);
let six = plus_one(five);
let none = plus_one(None);
println!("five: {:?}", five);
println!("six: {:?}", six);
println!("none: {:?}", none);
}
匹配穷尽性
fn main() {
let some_u8_value = 0u8;
match some_u8_value {
1 => println!("一"),
3 => println!("三"),
5 => println!("五"),
7 => println!("七"),
_ => println!("其他数字"), // 匹配所有其他情况
}
}
if let 简洁控制流
fn main() {
let some_value = Some(5);
// 使用 match
match some_value {
Some(x) => println!("值是: {}", x),
_ => println!("没有值"),
}
// 使用 if let(更简洁)
if let Some(x) = some_value {
println!("值是: {}", x);
}
}
while let 条件循环
fn main() {
let mut optional = Some(0);
while let Some(i) = optional {
if i > 5 {
println!("大于 5,退出");
optional = None;
} else {
println!("i 是 {:?},尝试 again", i);
optional = Some(i + 1);
}
}
}
实际应用示例
创建一个简单的图形库
#[derive(Debug)]
enum Shape {
Circle { radius: f64 },
Rectangle { width: f64, height: f64 },
Triangle { base: f64, height: f64 },
}
impl Shape {
fn area(&self) -> f64 {
match self {
Shape::Circle { radius } => std::f64::consts::PI * radius * radius,
Shape::Rectangle { width, height } => width * height,
Shape::Triangle { base, height } => 0.5 * base * height,
}
}
}
fn main() {
let shapes = vec![
Shape::Circle { radius: 5.0 },
Shape::Rectangle { width: 10.0, height: 5.0 },
Shape::Triangle { base: 8.0, height: 6.0 },
];
for shape in &shapes {
println!("形状: {:?}, 面积: {:.2}", shape, shape.area());
}
}
状态机示例
#[derive(Debug)]
enum State {
Locked,
Open,
}
#[derive(Debug)]
enum Event {
Coin,
Push,
}
fn transition(state: State, event: Event) -> State {
match (state, event) {
(State::Locked, Event::Coin) => State::Open,
(State::Open, Event::Push) => State::Locked,
_ => state,
}
}
fn main() {
let mut state = State::Locked;
println!("初始状态: {:?}", state);
state = transition(state, Event::Coin);
println!("投入硬币后: {:?}", state);
state = transition(state, Event::Push);
println!("推门后: {:?}", state);
}
总结
本教程详细介绍了 Rust 的结构体与枚举:
-
结构体:
- 定义和创建结构体
- 访问结构体字段
- 结构体更新语法
- 元组结构体和类单元结构体
- 结构体数据的所有权
-
方法:
- 定义方法
&self参数- 带有更多参数的方法
- 关联函数
- 多个 impl 块
-
枚举:
- 定义枚举
- 枚举变体中的数据
- 枚举方法
- Option 枚举
- Option 的优势
-
match 控制流:
- 基本 match
- 绑定值
- 匹配 Option
- 匹配穷尽性
- if let 简洁控制流
- while let 条件循环
结构体和枚举是 Rust 中创建自定义类型的基础,掌握它们对于编写 Rust 代码至关重要。它们与模式匹配结合,提供了强大的类型安全保证。
下一步
在下一教程中,我们将学习 Rust 的错误处理,包括:
-
Result 类型
-
panic! 宏
-
错误处理的最佳实践
-
自定义错误类型
继续学习 Rust,掌握这门强大语言的更多特性!

