目录
匹配命名变量的覆盖问题
fn main() {
let x = Some(5);
let y = 10;
match x {
Some(50) => println!("Got 50"),
Some(y) => println!("Matched, y = {:?}", y),
//这里的y不会读取外部的y变量, 而是some(y)匹配上的值,本例中就是5,而不是10
//这在一定程度上造成了歧义,也让默认分支失去了意义
_ => println!("Default case, x = {:?}", x),
}
//当然随着match表达式的结束,内部的y变量被释放,所以并没有对外部的y进行修改(只是内部覆盖)
println!("at the end: x = {:?}, y = {:?}", x, y);
}
如果你不想引入变量覆盖,那么需要使用匹配守卫(match guard)的方式
匹配守卫
匹配守卫(match guard)是一个位于
match
分支模式之后的额外if
条件,它能为分支模式提供更进一步的匹配条件。
fn main() {
let x = Some(5);
let y = 10;
match x {
Some(50) => println!("Got 50"),
Some(n) if n < y => println!("Matched, n = {}", n),
//这里让 n与y 真正发生了关系---相等,同时并没有覆盖外部的变量
//默认分支同时存在意义
_ => println!("Default case, x = {:?}", x),
}
println!("at the end: x = {:?}, y = {}", x, y);
}
@绑定
@
(读作 at)运算符允许为一个字段绑定另外一个变量
fn main() {
enum Message {
Hello { id: i32 },
}
let msg = Message::Hello { id: 5 };
match msg {
Message::Hello { id: id_variable @ 3..=7 } => {
println!("Found an id in range: {}", id_variable)
//注意这里是不能读取id的,因为id绑定到另外一个变量id_variable中,且为id_variable设定3到7的限制范围
},
Message::Hello { id: 10..=12 } => {
println!("Found an id in another range")
//注意这里也是不能读取id的
},
Message::Hello { id } => {
println!("Found some other id: {}", id)
//这里却是可以读取id的
},
}
}
第二个分支只在模式中指定了一个范围,
id
字段的值可以是10、11 或 12
,不过这个模式的代码并不知情也不能使用id
字段中的值,因为没有将id
值保存进一个变量。
@绑定转换为匹配守卫
fn main() {
enum Message {
Hello { id: i32 },
}
let msg = Message::Hello { id: 11 };
match msg {
Message::Hello { id } if id >3 && id <7 => {
println!("Found an id in range: {}", id)
},
Message::Hello { id } if id >10 && id<12 => {
println!("Found an id in another range , {}" , id)
},
Message::Hello { id } => {
println!("Found some other id: {}", id)
},
}
}
但其实我们会发现这是这种转换关系的非常麻烦的,也就是不建议这样使用,因为只需要一个分支并在其内部进行if判断更加直截了当
match msg {
Message::Hello { id } => {
if id >3 && id <7{
println!("Found an id in range: {}", id)
}
else if id >10 && id<12{
println!("Found an id in another range , {}" , id)
}
else{
println!("Found some other id: {}", id)
}
}
}
总结
综上可以知道,匹配守卫可以解决变量覆盖问题,匹配守卫还可以与@绑定相互转换,有时候匹配守卫写法更加简单;