阶段三:结构体与枚举
核心知识点
-
结构体(Struct)
- 自定义复合数据类型,包含多个命名字段
- 通过
impl块为结构体添加方法 - 关联函数(类似静态方法)
-
枚举(Enum)
- 定义一组可能的值(变体)
- 可携带数据(类似联合类型)
- 模式匹配(
match表达式)
-
模式匹配(Pattern Matching)
- 用
match处理枚举变体 - 通配符
_和占位符.. if let简化单分支匹配
- 用
学习步骤
1. 结构体定义与实例化
// 定义结构体
struct User {
username: String,
email: String,
sign_in_count: u64,
active: bool,
}
// 创建实例
let user1 = User {
email: String::from("alice@example.com"),
username: String::from("alice"),
active: true,
sign_in_count: 1,
};
2. 为结构体添加方法
impl User {
// 关联函数(类似构造函数)
fn new(email: String, username: String) -> Self {
User {
email,
username,
active: true,
sign_in_count: 0,
}
}
// 方法(第一个参数为 `&self`)
fn deactivate(&mut self) {
self.active = false;
}
}
3. 枚举与模式匹配
// 定义枚举
enum WebEvent {
PageLoad, // 无数据
KeyPress(char), // 携带字符
Click { x: i64, y: i64 }, // 匿名结构体
}
// 处理枚举
fn handle_event(event: WebEvent) {
match event {
WebEvent::PageLoad => println!("页面加载"),
WebEvent::KeyPress(c) => println!("按下键: {}", c),
WebEvent::Click { x, y } => println!("点击坐标: ({}, {})", x, y),
}
}
练习题
题目1:计算矩形面积
struct Rectangle {
width: u32,
height: u32,
}
impl Rectangle {
// 实现方法 `area`
fn area(&self) -> u32 {
self.width * self.height
}
// 关联函数 `square` 创建正方形
fn square(size: u32) -> Self {
Rectangle {
width: size,
height: size,
}
}
}
fn main() {
let rect = Rectangle { width: 30, height: 50 };
println!("面积: {}", rect.area()); // 输出 1500
let square = Rectangle::square(10);
println!("正方形面积: {}", square.area()); // 输出 100
}
题目2:处理消息枚举
enum Message {
Quit,
Move { x: i32, y: i32 },
Write(String),
ChangeColor(u8, u8, u8),
}
fn process_message(msg: Message) {
match msg {
Message::Quit => println!("退出程序"),
Message::Move { x, y } => println!("移动到坐标 ({}, {})", x, y),
Message::Write(text) => println!("文本消息: {}", text),
Message::ChangeColor(r, g, b) => println!("颜色变更为 RGB({}, {}, {})", r, g, b),
}
}
fn main() {
let messages = vec![
Message::Quit,
Message::Move { x: 10, y: 20 },
Message::Write(String::from("Hello Rust")),
Message::ChangeColor(255, 0, 0),
];
for msg in messages {
process_message(msg);
}
}
题目3:自定义 Option
// 实现一个简化版 Option<T>
enum MyOption<T> {
MySome(T),
MyNone,
}
impl<T> MyOption<T> {
// 实现 unwrap 方法
fn unwrap(self) -> T {
match self {
MyOption::MySome(val) => val,
MyOption::MyNone => panic!("尝试解包 MyNone 值"),
}
}
}
fn main() {
let some_val = MyOption::MySome(42);
println!("解包结果: {}", some_val.unwrap()); // 输出 42
let none_val: MyOption<i32> = MyOption::MyNone;
// none_val.unwrap(); // 运行时 panic
}
常见错误与修复
-
错误:
missing field 'email' in initializer- 原因:结构体实例化时缺少字段
- 修复:补全所有字段或使用
..语法继承其他字段let user2 = User { email: String::from("bob@example.com"), username: String::from("bob"), ..user1 // 继承剩余字段 };
-
错误:
non-exhaustive patterns- 原因:
match未覆盖所有枚举变体 - 修复:添加
_通配分支match msg { Message::Quit => { /* ... */ }, _ => println!("其他消息类型"), }
- 原因:
扩展知识
-
元组结构体(Tuple Struct)
- 无名字段的结构体,用于轻量级封装
struct Point(i32, i32); let origin = Point(0, 0); -
模式守卫(Pattern Guard)
- 在
match分支中添加条件判断
match value { Some(x) if x > 10 => println!("大于10"), Some(x) => println!("值为 {}", x), None => println!("无值"), } - 在