Rust 2.9 匹配
11 Jan 2015 by LelouchHe
简单的if/else
一般是不够的,因为我们经常需要多于2个的选择.而且,else
的情况有时会非常复杂,此时该怎么办呢?
Rust有一个match
关键字,用来替代复杂的if/else
.如下:
let x = 5;
match x {
1 => println!("one"),
2 => println!("two"),
3 => println!("three"),
4 => println!("four"),
5 => println!("five"),
_ => println!("something else"),
}
match
后接一个表达式,然后根据表达式的值进行选择.每个分支都是val => expression
的格式.当值匹配时,相应的表达式就会求值.这是一种模式匹配(pattern matching),所以该关键字称为match
.
这样做的优点是什么?首先,match
强制保证了穷尽检查(exhaustiveness checking).请看上面的最后一个下划线(“_“)的分支,如果我们去掉这个,Rust会编译出错:
error: non-exhaustive patterns: `_` not covered
换句话说,Rust告诉我们存在遗漏的情况.因为x
是一个整数,Rust知道它还有一些其他的值,比如6.如果没有_
的话,这个情况就没法覆盖了,所以Rust就无法编译通过._
充当了”其余所有”的分支.如果其他分支都没有匹配,_
的分支就会执行,只要有了这个,我们就对所有的x
的取值都有了匹配的分支,所以我们的程序就能编译通过了.
match
还能解析enum.还记得上节的代码么?
use std::cmp::Ordering;
fn cmp(a: i32, b: i32) -> Ordering {
if a < b { Ordering::Less }
else if a > b { Ordering::Greater }
else { Ordering::Equal }
}
fn main() {
let x = 5;
let y = 10;
let ordering = cmp(x, y);
if ordering == Ordering::Less {
println!("less");
} else if ordering == Ordering::Greater {
println!("greater");
} else {
println!("equal");
}
}
我们可以这样重写:
use std::cmp::Ordering;
fn cmp(x: i32, y: i32) -> Ordering {
if a < b { Ordering::Less }
else if a > b { Ordering::Greater }
else { Ordering::Equal }
}
fn main() {
let x = 5;
let y = 10;
match cmp(x, y) {
Ordering::Less => println!("less");
Ordering::Greater => println!("less");
Ordering::Equal => println!("less");
}
}
这个版本的代码噪音更少,而且将Ordering
的所有情况都覆盖了.要是使用if/else
,我们遗漏了一些情况(比如Ordering::Greater
),程序可以编译通过的.但使用了match
,程序无法编译通过.Rust可以保证我们覆盖了所有的情况.
match
表达式还能获取包含在枚举类型中的值,比如:
enum OptionalInt {
Value(i32),
Missing,
}
fn main() {
let x = OptionalInt::Value(5);
let y = OptionalInt::Missing;
match x {
OptionalInt::Value(n) => println!("x is {}", n),
OptionalInt::Missing => println!("x is missing!"),
}
match y {
OptionalInt::Value(n) => println!("y is {}", n),
OptionalInt::Missing => println!("y is missing!"),
}
}
这就是如何获取枚举类型中的值.这也让我们可以处理错误或非预期的错误;比如,一个函数无法保证会返回整型(这里的i32
),就可以返回OptionalInt
,我们可以通过match
来处理.可以看到,枚举和match
在一起是非常有用的.
match
也是一个表达式,我们可以把它放到let
绑定的右边,或者任意需要表达式的地方.我们可以这样来实现上面的例子:
use std::cmp::Ordering;
fn cmp(x: i32, y: i32) -> Ordering {
if a < b { Ordering::Less }
else if a > b { Ordering::Greater }
else { Ordering::Equal }
}
fn main() {
let x = 5;
let y = 10;
println!("{}", match cmp(x, y) {
Ordering::Less => "less",
Ordering::Greater => "greater",
Ordering::Equal => "equal",
});
}
有时,这是个非常有用的模式.