知识点1:定义和使用枚举
枚举让你定义一个类型,它只能是几种固定值之一:
rust
// 定义枚举
enum Direction {
Up,
Down,
Left,
Right,
}
fn main() {
// 创建枚举值
let dir = Direction::Up;
// 用 match 匹配(必须穷举所有情况)
match dir {
Direction::Up => println!("向上移动"),
Direction::Down => println!("向下移动"),
Direction::Left => println!("向左移动"),
Direction::Right => println!("向右移动"),
}
// 用 if let 只匹配一种情况
if let Direction::Up = dir {
println!("当前方向是上");
}
}
知识点2:带数据的枚举
枚举的每个变体可以携带不同类型的数据:
rust
enum Message {
Quit, // 无数据
Move { x: i32, y: i32 }, // 携带具名字段
Write(String), // 携带一个 String
ChangeColor(u8, u8, u8), // 携带三个 u8
}
fn main() {
let msgs = vec![
Message::Quit,
Message::Move { x: 10, y: 20 },
Message::Write(String::from("你好")),
Message::ChangeColor(255, 0, 128),
];
for msg in msgs {
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);
}
}
}
}
知识点3:给枚举添加方法
rust
enum Coin {
Penny,
Nickel,
Dime,
Quarter,
}
impl Coin {
// 关联函数
fn all() -> Vec<Coin> {
vec![Coin::Penny, Coin::Nickel, Coin::Dime, Coin::Quarter]
}
// 方法:返回面值(美分)
fn value(&self) -> u32 {
match self {
Coin::Penny => 1,
Coin::Nickel => 5,
Coin::Dime => 10,
Coin::Quarter => 25,
}
}
// 方法:返回名称
fn name(&self) -> &str {
match self {
Coin::Penny => "一分钱",
Coin::Nickel => "五分钱",
Coin::Dime => "一角钱",
Coin::Quarter => "二十五分钱",
}
}
}
fn main() {
for coin in Coin::all() {
println!("{} = {}美分", coin.name(), coin.value());
}
}
知识点4:Option 和 Result(标准库中的枚举)
Rust 没有 null,用 Option 表示"可能有值,也可能没有":
rust
fn find_first_even(numbers: &[i32]) -> Option<i32> {
for &n in numbers {
if n % 2 == 0 {
return Some(n); // 找到了,返回 Some(值)
}
}
None // 没找到,返回 None
}
fn main() {
let nums = vec![1, 3, 5, 8, 9];
match find_first_even(&nums) {
Some(n) => println!("找到偶数: {}", n),
None => println!("没有偶数"),
}
// 常用方法
let result = find_first_even(&nums);
println!("是否有值: {}", result.is_some());
println!("取值或默认: {}", result.unwrap_or(0));
}
Result 用于可能出错的操作:
rust
fn divide(a: f64, b: f64) -> Result<f64, String> {
if b == 0.0 {
Err(String::from("除数不能为零"))
} else {
Ok(a / b)
}
}
fn main() {
match divide(10.0, 3.0) {
Ok(result) => println!("结果: {}", result),
Err(e) => println!("错误: {}", e),
}
match divide(10.0, 0.0) {
Ok(result) => println!("结果: {}", result),
Err(e) => println!("错误: {}", e),
}
}
核心规则
概念 写法
定义枚举 enum Name { A, B, C }
带数据变体 Variant(Type) 或 Variant { field: Type }
创建枚举值 Name::Variant 或 Name::Variant(data)
匹配枚举 match 必须穷举所有变体
只匹配一种 if let Name::Variant = value
通配符 _ => ... 匹配剩余情况
Option 有值 Some(value)
Option 无值 None
Result 成功 Ok(value)
Result 失败 Err(error)
动手试试
补全下面的代码:
rust
// 补全:定义一个 Shape 枚举,包含以下变体:
// Circle(f64) --- 半径
// Rectangle(f64, f64) --- 宽和高
// Triangle(f64, f64, f64) --- 三条边
// 补全:为 Shape 实现以下方法:
// 1. area(&self) -> f64
// - Circle: π * r²(用 std::f64::consts::PI)
// - Rectangle: 宽 * 高
// - Triangle: 用海伦公式 √(s(s-a)(s-b)(s-c)),s = (a+b+c)/2
// 2. perimeter(&self) -> f64
// - Circle: 2πr
// - Rectangle: 2(宽+高)
// - Triangle: a+b+c
// 3. describe(&self) -> String
// 返回格式如 "圆形(半径=5)" / "矩形(宽=3, 高=4)" / "三角形(边=3,4,5)"
fn main() {
let shapes = vec![
Shape::Circle(5.0),
Shape::Rectangle(3.0, 4.0),
Shape::Triangle(3.0, 4.0, 5.0),
];
for shape in &shapes {
// 补全:打印每个形状的描述、面积和周长
// 面积保留2位小数,周长保留2位小数
}
// 期望输出:
// 圆形(半径=5): 面积=78.54, 周长=31.42
// 矩形(宽=3, 高=4): 面积=12.00, 周长=14.00
// 三角形(边=3,4,5): 面积=6.00, 周长=12.00
}
期望输出:
圆形(半径=5): 面积=78.54, 周长=31.42
矩形(宽=3, 高=4): 面积=12.00, 周长=14.00
三角形(边=3,4,5): 面积=6.00, 周长=12.00
写好了贴过来,没问题就进入第14课:模式匹配 Pattern Matching 👋
贴代码
rust
// 定义 Shape 枚举
#[derive(Debug)]
enum Shape {
Circle(f64), // 半径
Rectangle(f64, f64), // 宽和高
Triangle(f64, f64, f64), // 三条边
}
// 为 Shape 实现方法
impl Shape {
// 1. 面积
fn area(&self) -> f64 {
match self {
Shape::Circle(r) => std::f64::consts::PI * r * r,
Shape::Rectangle(w, h) => w * h,
Shape::Triangle(a, b, c) => {
let s = (a + b + c) / 2.0;
(s * (s - a) * (s - b) * (s - c)).sqrt()
}
}
}
// 2. 周长
fn perimeter(&self) -> f64 {
match self {
Shape::Circle(r) => 2.0 * std::f64::consts::PI * r,
Shape::Rectangle(w, h) => 2.0 * (w + h),
Shape::Triangle(a, b, c) => a + b + c,
}
}
// 3. 描述信息
fn describe(&self) -> String {
match self {
Shape::Circle(r) => format!("圆形(半径={})", r),
Shape::Rectangle(w, h) => format!("矩形(宽={}, 高={})", w, h),
Shape::Triangle(a, b, c) => format!("三角形(边={},{},{})", a, b, c),
}
}
}
fn main() {
let shapes = vec![
Shape::Circle(5.0),
Shape::Rectangle(3.0, 4.0),
Shape::Triangle(3.0, 4.0, 5.0),
];
for shape in &shapes {
// 打印每个形状的描述、面积和周长,保留2位小数
println!(
"{}: 面积={:.2}, 周长={:.2}",
shape.describe(),
shape.area(),
shape.perimeter()
);
}
}
运行输出
plaintext
圆形(半径=5): 面积=78.54, 周长=31.42
矩形(宽=3, 高=4): 面积=12.00, 周长=14.00
三角形(边=3,4,5): 面积=6.00, 周长=12.00
枚举核心知识点
- enum(枚举):一个类型可以代表多种不同的数据变体;变体里面可以直接存放数据(元组枚举)。
- match 模式匹配:处理枚举必须用 match,对每一种分支分别计算逻辑。
- std::f64::consts::PI :Rust 标准库提供的圆周率常量。
- 海伦公式: s=(a+b+c)/2 ,面积 = √s(s−a)(s−b)(s−c)。
- 格式化 {:.2} :浮点数保留两位小数输出。
- 遍历的时候 &shapes ,使用借用,不转移所有权。
对比结构体:struct 用来保存一种事物的数据;enum 用来表示多种不同类型的事物。
枚举练习完成!结构体+枚举两大自定义类型就学完了。
需要我出一道综合练习题(结构体+枚举+Option)吗?
Rust综合实战练习题(结构体 + 枚举 + Option + Vec + 方法 + match)
题目:图书订单管理系统
需求说明
- 定义枚举 OrderStatus ,订单状态,包含3个变体:
- Pending :待付款(无附加数据)
- Paid :已付款(存储付款时间字符串,例: "2026‑09‑05" )
- Cancelled :已取消(存储取消原因: String )
- 定义结构体 Book (复用前面练习版本)
rust
Book {
title: String,
price: f64,
}
实现构造方法 new(title:String, price:f64) -> Self
- 定义订单结构体 Order
- id: u32 (订单编号)
- book: Book (购买的图书)
- quantity: u32 (购买数量)
- status: OrderStatus(订单状态)
为 Order 实现3个方法:
① total_price(&self) -> f64 :订单总价 = 图书单价 × 购买数量
② pay(&mut self, pay_time: String) :
- 如果当前状态是 Pending ,修改状态为 Paid(pay_time)
- 如果已经是 Paid / Cancelled,不做任何操作
③ cancel(&mut self, reason: String) -> Option - 当前状态为 Pending:修改状态为 Cancelled(reason),返回 None (取消成功)
- 已经付款:取消失败,返回 Some(format!("订单{}已付款,无法取消",self.id))
- main函数逻辑
- 创建一个 Vec 订单列表,初始化两条订单:
订单1:id=1,book:《Rust入门》,价格59.0,数量=2,状态Pending
订单2:id=2,book:《算法教程》,价格45.0,数量=1,状态Paid("2026‑09‑01") - 调用订单1的pay方法,传入付款时间:"2026‑09‑05"
- 调用订单2的cancel方法,传入原因:"用户临时不需要了";用match处理返回值,成功无输出,失败打印返回的错误消息。
- 遍历全部订单,编写一个print_order函数(或者直接循环内match)打印订单详情:
输出样例:
plaintext
订单#1:Rust入门 ×2,总价=118,状态:已付款(2026‑09‑05)
订单#2:算法教程 ×1,总价=45,状态:已付款(2026‑09‑01)
提示清单
- match匹配枚举分支,修改枚举状态的时候注意所有权;
- pay、cancel方法需要 &mut self,因为要修改订单;
- cancel 返回Option,取消成功返回None,失败返回Some(错误字符串);
- 无数据的枚举变体直接写 OrderStatus::Pending;
- 打印订单的时候,match匹配OrderStatus三个分支,输出不同文字。
动手写
先自己动手写,写完再对照参考答案👉点击展开完整参考答案
rust
// 订单状态枚举
#[derive(Debug)]
enum OrderStatus {
Pending,
Paid(String),
Cancelled(String),
}
// 图书结构体
#[derive(Debug)]
struct Book {
title: String,
price: f64,
}
impl Book {
fn new(title: String, price: f64) -> Self {
Book { title, price }
}
}
// 订单结构体
#[derive(Debug)]
struct Order {
id: u32,
book: Book,
quantity: u32,
status: OrderStatus,
}
impl Order {
// 订单总价
fn total_price(&self) -> f64 {
self.book.price * (self.quantity as f64)
}
// 付款操作
fn pay(&mut self, pay_time: String) {
if let OrderStatus::Pending = self.status {
self.status = OrderStatus::Paid(pay_time);
}
}
// 取消订单,返回Option,Some代表失败信息,None成功
fn cancel(&mut self, reason: String) -> Option<String> {
match &self.status {
OrderStatus::Pending => {
self.status = OrderStatus::Cancelled(reason);
None
}
OrderStatus::Paid(_) | OrderStatus::Cancelled(_) => {
Some(format!("订单{}已付款,无法取消", self.id))
}
}
}
}
fn main() {
// 创建订单集合
let mut orders = vec![
Order {
id: 1,
book: Book::new(String::from("Rust入门"), 59.0),
quantity: 2,
status: OrderStatus::Pending,
},
Order {
id: 2,
book: Book::new(String::from("算法教程"), 45.0),
quantity: 1,
status: OrderStatus::Paid(String::from("2026‑09‑01")),
},
];
// 订单1付款
orders[0].pay(String::from("2026‑09‑05"));
// 订单2尝试取消,match处理返回结果
let res = orders[1].cancel(String::from("用户临时不需要了"));
match res {
Some(msg) => println!("{}", msg),
None => (),
}
// 遍历打印订单
for order in &orders {
let status_text = match &order.status {
OrderStatus::Pending => "待付款".to_string(),
OrderStatus::Paid(t) => format!("已付款({})", t),
OrderStatus::Cancelled(r) => format!("已取消({})", r),
};
println!(
"订单#{}:{} ×{},总价={},状态:{}",
order.id,
order.book.title,
order.quantity,
order.total_price(),
status_text
);
}
}
运行输出
plaintext
订单2已付款,无法取消
订单#1:Rust入门 ×2,总价=118,状态:已付款(2026‑09‑05)
订单#2:算法教程 ×1,总价=45,状态:已付款(2026‑09‑01)
关键知识点复盘
- if let :只关心枚举某一个分支的简化匹配语法,比完整match简洁;
- 模式匹配多分支 | : Paid()|Cancelled() 一条匹配多个变体;
- Option作为函数返回值用来表示操作成功/失败,不用panic;
- 结构体嵌套(Order里面包含Book),真实业务开发非常常见;
- 集合Vec存储多个业务对象,循环遍历处理;
- to_string() / format! 构造动态字符串。
做完这道,Rust入门基础语法(变量、循环、函数、元组、数组、Vec、HashMap、结构体、枚举、Option、Result、模式匹配)全部通关。
接下来就可以进入 所有权、借用、生命周期 这一Rust最核心、最难的模块,需要开启所有权专项练习吗?