Rust Lang Book Ch.18 Patterns and Matching
Rust中的Pattern能够包含以下内容:
a) literal
b)Destructured arrays, enums, structs, or tuples
c) 变量
d) 通配符
e) placeholders
以下的都算是pattern:
a) match Arms
b) if let
c) while let
d) for x in y 中的x
e) let PATTERN = EXPRESSION
f) function parameters, 例如&(x, y): &(i32, i32)
Refutability
能够match任何传过来的值的是irrefutable pattern。例如let x = 5中的x。
与此对应的,有时可能match不了传过来的值的是refutable pattern,例如let Some(x) = some_option_value;
一般来说,写程序时可以不重视pattern的Refutable和irrefutable之间的差别,但是,在弹出错误信息的时候要能够区别。P.S: Rust只允许match的最多一个arm是irrefutable match。
Pattern Syntax
1. 和固定值(literal)做对比
let x = 1;
match x {
1 => println!("one"),
2 => println!("two"),
3 => println!("three"),
_ => println!("anything"),
}
2. Named Variable
let y = 5中的y是一个named variable也是一个irrefutable pattern。
但是named variable也可能只是pattern的一部分。
let x = Some(5);
let y = 10;
match x {
Some(50) => println!("Got 50"),
Some(y) => println!("Matched, y = {:?}", y),
_ => println!("Default case, x = {:?}", x),
}
println!("at the end: x = {:?}, y = {:?}", x, y);
//Output:
//Matched, y = 5
//注意在这里match内是一个新的作用域了,里面的Some(y)里面的y是个named variable,与外层的y=10无关
Multiple Patterns
可以用|把多个pattern连起来。
let x = 1;
match x {
1 | 2 => println!("one or two"),
3 => println!("three"),
_ => println!("anything"),
}
Matching Ranges
使用..=可以一次性匹配一个全闭区间。..=只能和数字或者char搭配使用。
let x = 5;
match x {
1..=5 => println!("one through five"),
_ => println!("something else"),
}
let x = 'c'; match x { 'a'..='j' => println!("early ASCII letter"), 'k'..='z' => println!("late ASCII letter"), _ => println!("something else"), }
Destructuring
Destructuring Structs
可以带域名,直接按顺序取named variable,也可以在给一部分域名中嵌套其他pattern
struct Point {
x: i32,
y: i32,
}
fn main() {
let p = Point { x: 0, y: 7 };
let Point { x: a, y: b } = p;
assert_eq!(0, a);
assert_eq!(7, b);
let Point {x, y} = p;
assert_eq!(0, x);
}
fn main() {
let p = Point { x: 0, y: 7 };
match p {
Point { x, y: 0 } => println!("On the x axis at {}", x),
Point { x: 0, y } => println!("On the y axis at {}", y),
Point { x, y } => println!("On neither axis: ({}, {})", x, y),
}
}
Destructuring Enums
enum Message {
Quit,
Move { x: i32, y: i32 },
Write(String),
ChangeColor(i32, i32, i32),
}
fn main() {
let msg = Message::ChangeColor(0, 160, 255);
match msg {
Message::Quit => {
println!("The Quit variant has no data to destructure.")
}
Message::Move { x, y } => {
println!(
"Move in the x direction {} and in the y direction {}",
x, y
);
}
Message::Write(text) => println!("Text message: {}", text),
Message::ChangeColor(r, g, b) => println!(
"Change the color to red {}, green {}, and blue {}",
r, g, b
),
}
}
Destructuring Nested Structs and Enums
enum Color {
Rgb(i32, i32, i32),
Hsv(i32, i32, i32),
}
enum Message {
Quit,
Move { x: i32, y: i32 },
Write(String),
ChangeColor(Color),
}
fn main() {
let msg = Message::ChangeColor(Color::Hsv(0, 160, 255));
match msg {
Message::ChangeColor(Color::Rgb(r, g, b)) => println!(
"Change the color to red {}, green {}, and blue {}",
r, g, b
),
Message::ChangeColor(Color::Hsv(h, s, v)) => println!(
"Change the color to hue {}, saturation {}, and value {}",
h, s, v
),
_ => (),
}
}
Destructuring Structs and Tuples
let ((feet, inches), Point { x, y }) = ((3, 10), Point { x: 3, y: -10 });
Ignore
忽略整个待匹配值:_
fn foo(_: i32, y: i32) { println!("This code only uses the y parameter: {}", y); }
忽略部分待匹配值:嵌套的_
match (setting_value, new_setting_value) {
(Some(_), Some(_)) => {
println!("Can't overwrite an existing customized value");
}
_ => {
setting_value = new_setting_value;
}
}
忽略一个没使用过的变量而不输出警告:在变量名前面加_
fn main() {
let _x = 5;
let y = 10;
}
忽略没匹配完的值: ..
match origin {
Point { x, .. } => println!("x is {}", x),
}
fn main() {
let numbers = (2, 4, 8, 16, 32);
match numbers {
(first, .., last) => {
println!("Some numbers: {}, {}", first, last);
}
}
}
但是要避免二义性:
fn main() {
let numbers = (2, 4, 8, 16, 32);
//error: `..` can only be used once per tuple pattern
match numbers {
(.., second, ..) => {
-- ^^ can only be used once per tuple pattern
println!("Some numbers: {}", second)
},
}
}
Match Guards
match guard是match arm之后接着的一个if条件,要求match arm和if 都被满足时才能够匹配。能够支持比pattern更强大的条件。
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),
_ => println!("Default case, x = {:?}", x),
}
println!("at the end: x = {:?}, y = {}", x, y);
}
注意与|连用时,相当于任何一个pattern匹配之后,都要额外匹配这个if语句。
let x = 4;
let y = false;
match x {
4 | 5 | 6 if y => println!("yes"),
//无论是4,5还是6都需要匹配if y
_ => println!("no"),
}
@Bindings
@操作符允许程序员在同一个pattern中把变量保存下来同时测试是否满足条件。基本方法是fieldname: alias @ test_pattern
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),
Message::Hello { id: 10..=12 } => {
//没有使用@,为了10..=12这个测试,就无法保留named variable
println!("Found an id in another range")
}
Message::Hello { id } => println!("Found some other id: {}", id),
}

浙公网安备 33010602011771号