【Rust】05-结构体、枚举与模式匹配

结构体、枚举与模式匹配

学习目标

  • 使用结构体组织相关数据。
  • 使用枚举表达有限状态。
  • 掌握 match 和 if let 的基本用法。

结构体

结构体用于给一组相关字段命名:

rust 复制代码
struct User {
    name: String,
    email: String,
    active: bool,
}

fn main() {
    let user = User {
        name: String::from("Alice"),
        email: String::from("alice@example.com"),
        active: true,
    };

    println!("{} <{}>", user.name, user.email);
}

字段默认不可变。如果需要修改字段,整个结构体绑定必须是 mut:

rust 复制代码
let mut user = User {
    name: String::from("Alice"),
    email: String::from("alice@example.com"),
    active: true,
};

user.active = false;

Rust 不支持只把某个字段标记为可变。

字段初始化简写

当变量名和字段名相同时,可以简写:

rust 复制代码
struct User {
    name: String,
    email: String,
}

fn build_user(name: String, email: String) -> User {
    User { name, email }
}

结构体更新语法

可以基于已有结构体创建新值:

rust 复制代码
struct Settings {
    theme: String,
    page_size: u32,
    notifications: bool,
}

fn main() {
    let default = Settings {
        theme: String::from("light"),
        page_size: 20,
        notifications: true,
    };

    let custom = Settings {
        theme: String::from("dark"),
        ..default
    };

    println!("{}", custom.theme);
}

注意:如果被移动的字段不是 Copy,使用 ..default 后,default 可能不再完整可用。

方法

使用 impl 给结构体定义方法:

rust 复制代码
struct Rectangle {
    width: u32,
    height: u32,
}

impl Rectangle {
    fn area(&self) -> u32 {
        self.width * self.height
    }
}

fn main() {
    let rect = Rectangle {
        width: 30,
        height: 50,
    };

    println!("{}", rect.area());
}

&self 是 self: &Self 的简写,表示方法借用当前实例。

枚举

枚举用于表达一个值只能是若干变体之一:

rust 复制代码
enum Direction {
    Up,
    Down,
    Left,
    Right,
}

枚举变体可以携带数据:

rust 复制代码
enum Message {
    Quit,
    Move { x: i32, y: i32 },
    Write(String),
    ChangeColor(u8, u8, u8),
}

这让枚举非常适合表达状态机、命令、协议消息和错误类型。

match

match 会穷尽处理所有可能分支:

rust 复制代码
enum Direction {
    Up,
    Down,
    Left,
    Right,
}

fn describe(direction: Direction) -> &'static str {
    match direction {
        Direction::Up => "go up",
        Direction::Down => "go down",
        Direction::Left => "go left",
        Direction::Right => "go right",
    }
}

如果遗漏某个分支,编译器会报错。

if let

当只关心一个模式时,可以使用 if let:

rust 复制代码
fn main() {
    let value = Some(3);

    if let Some(number) = value {
        println!("number={number}");
    }
}

这比只为了处理一个分支写完整 match 更简洁。

常见误区

  • 结构体字段可变性由变量绑定决定,不由字段单独决定。
  • match 必须穷尽所有情况,这是优点,不是麻烦。
  • 枚举不是只能表示无数据标签;它的变体可以携带不同形状的数据。
  • if let 适合单分支,复杂逻辑仍建议使用 match。

练习

  1. 定义一个 Book 结构体,包含标题、作者和页数。
  2. 给 Book 实现一个 summary 方法。
  3. 定义一个 TaskStatus 枚举,包含 Todo、Doing、Done,用 match 打印状态说明。

后记

2026年6月10日17点14分于上海。

相关推荐
Decay__1 小时前
05_MySQL 常用 SQL 大全 —— 诊断、管理、优化辅助 SQL 与三大系统库速查
运维·数据库·sql·mysql·架构
学长毕设4 小时前
基于SpringBoot的实验室资产管理系统
java·spring boot·后端
zzu123zsw5 小时前
从臃肿的模板调用到声明式契约:深入 UniHttp 动态代理与多渠道生命周期扩展
java·spring boot·microsoft·unihttp
小徐不徐说5 小时前
C++ 接口与插件设计:从工厂注册到 Qt 动态插件
数据库·c++·qt·系统架构·程序设计
源码集结号6 小时前
云诊所门诊系统源码,基于SpringBoot+Vue.js架构,支持多租户设计与Docker容器化部署
java·spring boot·源码·医院信息系统·门诊系统·诊所系统
论文复现现场6 小时前
WRF、FEA 能用 L40S 加速吗?求解器检查、断点恢复与长期运行
java·数据库·算法·wrf·有限元分析·gpu计算·断点续算
啃瓜子的松鼠6 小时前
泛微OAe9-后端二开异步调用
java
Decay__7 小时前
04_MySQL DBA 日常运维手册 —— 会话管理、锁与阻塞、事务监控、慢查询与日志巡检
运维·数据库·sql·mysql·架构
秋天的怀念_David7 小时前
第二十一夜 · 数字黑洞与西西弗斯的惩罚
java·程序人生·算法
外收内放7 小时前
Python基础语法练习题(73)
java·前端·python