枚举
enum是一组变体的类型,每个变体可以携带不同类型与数量的数据,不是C的整数别名rustenum Message { Quit, // 不携带数据 Move { x: i32, y: i32 }, // 携带结构体字段 Write(String), // 携带一个值 ChangeColor(i32, i32, i32), // 携带元组 }与
java枚举的对比:java枚举是固定几个实例的类,Rust枚举的每个变体每次出现都能装不同的值,表达力接近密封类(sealed class)枚举搭配
match解构是Rust组织数据的方式,替代了其他语言的继承与联合类型
模式匹配
match对一个值做多路分支,模式可以解构枚举、元组、结构体与区间rustfn describe(n: i32) -> i32 { match n { 0 => 0, // 字面量 1..=9 => 1, // 区间 _ => -1, // 通配符兜底 } }match 必须穷尽所有可能,漏掉变体会编译不通过,新增变体后所有
match处编译器逐一报错,这是重构安全的来源match是表达式,每个分支产生一个值,各分支类型必须一致if let只处理单个模式,忽略其余情况;let else在模式不匹配时必须发散(提前return、panic或break)rustif let Some(x) = opt { } // 只关心 Some 的情况 let Some(x) = opt else { return; }; // 取出值,失败就提前返回
panic
panic!宏触发不可恢复错误:打印错误信息、展开栈并退出程序- 使用场景:程序自身的 bug(数组越界、断言失败、非法状态),而不是可预期的失败
- 调试时用
RUST_BACKTRACE=1环境变量查看完整调用栈
Option 与空值
Rust没有 null:空指针被称为"十亿美元错误",Rust把"可能没有值"编码进类型系统,用标准库枚举Option<T>表达rustenum Option<T> { Some(T), None, }编译器强制先从
Some中取出值才能使用:想用T就必须处理None,空指针错误在编译期暴露而不是运行期崩溃直接取值的方法:
unwrap()(是None就 panic)、expect("<信息>")(panic 时带上提示信息),适合原型与确信不为空的场景组合式惯用法:
map、and_then、unwrap_or、ok_or,链式处理避免层层matchrustlet len = opt.map(|s| s.len()).unwrap_or(0);
Result 与错误传播
可恢复错误用标准库枚举
Result<T, E>表达,Rust没有异常机制,错误是普通值,会出现在函数签名里,调用者无法忽略rustenum Result<T, E> { Ok(T), Err(E), }与
java的try/catch对比:异常可以不声明也不捕获,Result把失败路径写进类型,漏处理就是编译错误与
Go的对比:Go每层都要手写if err != nil { return err },Rust的?把同样的检查与返回压缩成一个后缀字符?运算符:成功时取出Ok里的值,失败时立即return Err,是展开match的语法糖rustfn read_num(s: &str) -> Result<i32, std::num::ParseIntError> { let n: i32 = s.trim().parse()?; // 出错时直接把 Err 返回给调用者 Ok(n * 2) }?会通过From自动把错误转换成目标类型,常用Box<dyn Error>承接各种错误,让main统一返回Resultrustfn main() -> Result<(), Box<dyn std::error::Error>> { let n = read_num("42")?; println!("{}", n); Ok(()) }取舍惯例:程序 bug 用
panic!,调用方有能力处理的失败用Result,二者的边界写在代码里而不是靠约定