文章题目来自:https://practice-zh.course.rs/pattern-match/patterns.html
1 🌟🌟 使用 | 可以匹配多个值, 而使用 …= 可以匹配一个闭区间的数值序列
fn main() {}
fn match_number(n: i32) {match n {// 匹配一个单独的值1 => println!("One!"),// 使用 `|` 填空,不要使用 `..` 或 `..=`__ => println!("match 2 -> 5"),// 匹配一个闭区间的数值序列6..=10 => {println!("match 6 -> 10")},_ => {println!("match 11 -> +infinite")}}
}
将前面学到的模式匹配进行集合就可以了
fn match_number(n: i32) {match n {// 匹配一个单独的值1 => println!("One!"),// 使用 `|` 填空,不要使用 `..` 或 `..=`2 | 3 | 4 | 5 => println!("match 2 -> 5"),// 匹配一个闭区间的数值序列6..=10 => {println!("match 6 -> 10")}others => {println!("match 11 -> +infinite")}}
}
2 🌟🌟🌟 @ 操作符可以让我们将一个与模式相匹配的值绑定到新的变量上
struct Point {x: i32,y: i32,
}fn main() {// 填空,让 p 匹配第二个分支let p = Point { x: __, y: __ };match p {Point { x, y: 0 } => println!("On the x axis at {}", x),// 第二个分支Point { x: 0..=5, y: y@ (10 | 20 | 30) } => println!("On the y axis at {}", y),Point { x, y } => println!("On neither axis: ({}, {})", x, y),}
}
这里的语法可能会让有些人非常疑惑:明明x
和y
就在这里,为什么我要再给y
绑定一个变量?如果你直接编译上述代码(我指的是修改了p
的赋值之后),你会遇到如下错误:
将y
改成p.y
就可以了。
我们先考虑另外一个场景:
fn age() -> u32 {15
}fn main() {println!("Tell me what type of person you are");match age() {0 => println!("I haven't celebrated my first birthday yet"),1..=12 => println!("I'm a child of age 1..12"),13..=19 => println!("I'm a teen of age 13..19"),_ => println!("I'm an old person of age others"),}
}
一个典型的根据年龄匹配打印的函数,那如果我希望将被匹配的值,也就是age()
的返回值打印出来呢?这就不太好办了。也许可以在println!
里再调用一次?你知道可以这么做只是因为这里age()
返回的值是固定的,如果它每次返回的值都不一样,显然不能这么做。
这时,@
绑定就派上用场了。
fn main() {println!("Tell me what type of person you are");match age() {0 => println!("I haven't celebrated my first birthday yet"),n @ 1..=12 => println!("I'm a child of age {:?}", n),n @ 13..=19 => println!("I'm a teen of age {:?}", n),n => println!("I'm an old person of age {:?}", n),}
}
我们将被匹配的值绑定到n
上,后续代码逻辑就可以使用了。
再考虑上面的例子,归根结底,每次匹配都只是将外部的变量和范围进行匹配,中间没有产生任何额外的变量。所以如果你想使用,要么使用原始的外部变量,要么进行一个@
绑定。而匹配所有值,本质上不是匹配,就是进行了一次绑定,所以绑定的值可以直接使用。
3
// 修复错误
enum Message {Hello { id: i32 },
}fn main() {let msg = Message::Hello { id: 5 };match msg {Message::Hello {id: 3..=7,} => println!("id 值的范围在 [3, 7] 之间: {}", id),Message::Hello { id: newid@10 | 11 | 12 } => {println!("id 值的范围在 [10, 12] 之间: {}", newid)}Message::Hello { id } => println!("Found some other id: {}", id),}
}
第一个需要用@
绑定,第二个需要全部匹配(落个括号)
// 修复错误
enum Message {Hello { id: i32 },
}fn main() {let msg = Message::Hello { id: 5 };match msg {Message::Hello {id:id@ 3..=7,} => println!("id 值的范围在 [3, 7] 之间: {}", id),Message::Hello { id: newid@(10 | 11 | 12) } => {println!("id 值的范围在 [10, 12] 之间: {}", newid)}Message::Hello { id } => println!("Found some other id: {}", id),}
}
4 🌟🌟 匹配守卫(match guard)是一个位于 match 分支模式之后的额外 if 条件,它能为分支模式提供更进一步的匹配条件。
// 填空让代码工作,必须使用 `split`
fn main() {let num = Some(4);let split = 5;match num {Some(x) __ => assert!(x < split),Some(x) => assert!(x >= split),None => (),}
}
事实上就是多一个if条件,来进一步匹配而已。
fn main() {let num = Some(4);let split = 5;match num {Some(x) if x < split => assert!(x < split),Some(x) => assert!(x >= split),None => (),}
}
5 🌟🌟🌟 使用 … 忽略一部分值
// 填空,让代码工作
fn main() {let numbers = (2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048);match numbers {__ => {assert_eq!(first, 2);assert_eq!(last, 2048);}}
}
可惜只能忽略一次
fn main() {let numbers = (2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048);match numbers {(first, .., last) => {assert_eq!(first, 2);assert_eq!(last, 2048);}}
}
6 🌟🌟 使用模式 &mut V 去匹配一个可变引用时,你需要格外小心,因为匹配出来的 V 是一个值,而不是可变引用
// 修复错误,尽量少地修改代码
// 不要移除任何代码行
fn main() {let mut v = String::from("hello,");let r = &mut v;match r {&mut value => value.push_str(" world!") }
}
思来想去,也只有这一种改法了。
fn main() {let mut v = String::from("hello,");let r = &mut v;match r {value => value.push_str(" world!") }
}
r
本身就是对string
的可变引用,如果想直接使用的话,没必要再引用一次。按图中的匹配,最后value
会是一个不可变string
,这样后面的操作就做不到了。