【Rust自学】6.3. 控制流运算符-match

📅 2026/7/23 18:48:10
【Rust自学】6.3. 控制流运算符-match
6.3 控制流运算符-match6.3.1. 什么是matchmatch允许一个值与一系列模式进行比较并执行与匹配模式对应的代码。模式可以是字面值、变量名、通配符等等。把match表达式想象成一台硬币分类机硬币沿着带有不同大小孔洞的轨道滑下每枚硬币都会从它遇到的第一个合适的孔洞落下。同样地一个值会依次经过match中的每个模式当它“适合”第一个模式时就会落入执行时要使用的关联代码块中。6.3.2.match的实际应用来看个例子编写一个函数接受一枚未知的美国硬币并以类似计数机的方式判断它是哪种硬币然后返回其价值以美分为单位。enum Coin { Penny,// 1美分 Nickel,// 5美分 Dime,// 10美分 Quarter,// 25美分 } fn value_in_cents(coin: Coin) - u8 { match coin { Coin::Penny 1, Coin::Nickel 5, Coin::Dime 10, Coin::Quarter 25, } }match关键字后面跟着一个表达式在本例中就是值coin。这看起来与if使用的条件表达式很像但有一个很大的区别if的条件必须是布尔值而match可以处理任何类型。本例中coin的类型是我们在第一行定义的Coin枚举。接下来是花括号。花括号里有四个分支英文叫arm每个分支都由待匹配的模式和对应的代码组成。第一个分支Coin::Penny 1,使用Coin::Penny作为模式。用来分隔模式和要运行的代码这里要运行的代码就是值1也就是返回1。不同分支之间用逗号分隔。当match表达式运行时它会把match后面的表达式——这里是coin——从上到下依次与各个分支比较。如果某个模式与值匹配就执行与该模式关联的代码如果不匹配就继续检查下一个分支。匹配成功的分支所对应的代码表达式会作为整个match表达式的值返回。例如如果match匹配到5美分硬币也就是Coin::Nickel那么整个表达式的结果就是5。又因为match表达式是value_in_cents中的最后一个表达式所以它的值——5——会作为函数的返回值。这里每个分支的代码都很简单所以用就够了。但如果某个分支包含多行代码就需要用花括号把这些行包起来。例如fn value_in_cents(coin: Coin) - u8 { match coin { Coin::Penny { println!(Lucky penny!); 1 } Coin::Nickel 5, Coin::Dime 10, Coin::Quarter 25, } }6.3.3. 绑定值的模式match的分支可以绑定到被匹配值的一部分从而可以从枚举变体中提取值。例如一位朋友正在尝试收集全部50个州的25美分硬币。当我们按硬币类型对零钱分类时还会标注每个25美分硬币关联的州名美国州太多了这里只写了Alabama和Alaska#[derive(Debug)] // 便于调试打印 enum UsState { Alabama, Alaska, } enum Coin { Penny, Nickel, Dime, Quarter(UsState), } fn value_in_cents(coin: Coin) - u8 { match coin { Coin::Penny { println!(Lucky penny!); 1 }, Coin::Nickel 5, Coin::Dime 10, Coin::Quarter(state) { println!(State quarter from {:?}!, state); 25 } } } fn main() { let c Coin::Quarter(UsState::Alaska); println!({}, value_in_cents(c)); }给代表25美分硬币的Coin变体关联一份数据也就是上面的UsState枚举。在value_in_cents函数中Quarter分支也需要相应调整。匹配模式从Coin::Quarter改成Coin::Quarter(state)意思是把Coin::Quarter关联的值绑定到变量state上这样在后面的代码块中就可以使用这个关联值。有些情况下可能不需要Coin::Quarter关联的值。这时可以用通配符_表示不关心内容Coin::Quarter(_)在main中先声明变量c存的是Coin::Quarter(UsState::Alaska)。也就是说它保存了Coin::Quarter变体关联值是UsState::Alaska变体。然后调用value_in_cents。来看输出State quarter from Alaska! 256.3.4. 匹配OptionT来分析上一篇文章 6.2. Option枚举 最后的代码示例fn main() { let x: i8 5; let y: Optioni8 Some(5); let sum match y { Some(value) x value, // 如果 y 是 Some则解包并相加 None x, // 如果 y 是 None则返回 x }; }如果y不是None就解包把Some关联的值绑定到value并返回x value。如果y是None就只返回x的值。6.3.5.match必须穷尽Rust要求match覆盖所有可能性这样才能保证代码安全有效。对上一段代码稍作修改fn main() { let x: i8 5; let y: Optioni8 Some(5); let sum match y { Some(value) x value, }; }输出error[E0004]: non-exhaustive patterns: None not covered -- src/main.rs:5:21 | 5 | let sum match y { | ^ pattern None not covered | note: Optioni8 defined here -- /Users/stanyin/.rustup/toolchains/stable-aarch64-apple-darwin/lib/rustlib/src/rust/library/core/src/option.rs:600:1 | 600 | pub enum OptionT { | ^^^^^^^^^^^^^^^^^^ ... 604 | None, | ---- not covered note: the matched value is of type Optioni8 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | 6 ~ Some(value) x value, 7 ~ None todo!(), |Rust发现没有覆盖None这种可能性所以报错。一旦补上处理None的分支就没问题了。如果可能性太多或者你不想处理其中一些情况可以使用通配符_。6.3.6. 通配符先照常写出你想处理的分支其余情况用通配符_代替。例如v是一个u8变量我们想判断v是否为0。use rand::Rng; // 使用外部 crate fn main(){ let v: u8 rand::thread_rng().gen_range(0..255); // 生成随机数 println!({}, v); match v { 0 println!(zero), _ println!(not zero), } }u8有256种可能的值用match自然不可能为每个值都写一个分支。因此可以为0写一个分支其余情况用通配符_代替。输出133 not zero