模式匹配
- 模式匹配通常由一下組件組成:
字面量碑诉。
解構的數(shù)組太示、枚舉、結構體或者元組帮孔。
變量雷滋。
通配符
占位符。
知識匯總
模式的不可失敗性和可失敗性
- 模式可以被分為不可失敗(irrefutable) 和可失敗(refutable)兩種類型文兢。
- 例如 let x = 5; 中的 x 便是不可失敗模式晤斩,因為它能夠匹配表達式右側的所有可能的返回值。
- 例如 if let Some(x) = a_value 中的 Some(x) 便是可失敗模式禽作,如果 a_value 變量的值時 None 而不是 Some尸昧,那么表達式左側的Some(x) 模式就會發(fā)生不匹配。
- 了解這些概念十分重要旷偿,比如 let Some(x) = a_value 就會造成編譯困擾烹俗,因為這個表達式是可失敗的那么就要放到 if 中去。
if let 表達式
- 舉例:
fn main() {
let favorite_color: Option<&str> = None;
let is_tuesday = false;
let age : Result<u8, _> = "34".parse();
if let Some(color) = favorite_color {
println!("Using your favorite color, {}, as the background", color);
} else if is_tuesday {
println!("Tuesday is green day!");
} else if let Ok(age) = age {
if age > 30 {
println!("Using purple as the background color");
} else {
println!("Using orange as the background color");
}
}
}
while let 條件循環(huán)模式匹配
- 例子:while let 會反復執(zhí)行同一個模式匹配直到出現(xiàn)失敗的情況萍程。
fn main() {
let mut stack = Vec::new();
stack.push(1);
stack.push(2);
stack.push(3);
while let Some(s) = stack.pop() {
println!("Stack value : {}", s);
}
}
for 循環(huán)進行元祖填充
- 例子:注意不要忘記調用 enumerate 生成一個元祖迭代器
fn main() {
let v = vec!["a", "b", "c"];
for (index, value) in v.iter().enumerate() {
println!("index : {}, value : {}",index, value );
}
}
let 關鍵字本身就是一種模式匹配的方式
- 例子:
// 如果模式元素中的數(shù)量與元祖的數(shù)量不符幢妄,那么就會導致匹配失敗。
let (x, y, z) = (1, 2, 3);
// 如果確實有的不需要茫负,可以通過 _ 或者 .. 進行省略
let (x, y, _) = (1, 2, 3);
函數(shù)參數(shù)也是模式匹配
- 可以看到模式匹配無處不在蕉鸳,函數(shù)的參數(shù)也是模式匹配。
- 例子:
// 實際上定義了一個元祖參數(shù)
fn print_coordinates(&(x, y): &(i32, i32)) {
println!(" Current location : ({}, {})", x, y);
}
fn main() {
let point = (55, 33);
print_coordinates(&point);
}
匹配字面量
- 例子:
fn main() {
let x = 1 ;
match x {
1 => {println!("One"); },
2 => {println!("Two"); },
// 注意下面必須加上如果不加會提示沒有窮盡所有解
_ => {println!("Other"); },
}
}
匹配命名變量
- 例子:
fn main() {
let x = Some(5);
let y = 10 ;
match x {
Some(50) => println!("Get 50"),
Some(y) => println!("Matched, y = {:?}", y ),
_ => println!("Default case, x = {:?}", x),
}
println!("at the end : x = {:?}, y = {:?}", x, y);
}
多重匹配
- 例子:
fn main() {
let x = 1 ;
match x {
1 | 2 => println!("one or two"),
3 => println!("three"),
_ => println!("anything."),
}
}
使用 ... 來匹配區(qū)間
- 例子:
fn main() {
let x = 7;
match x {
1 ... 9 => println!("one through nine"),
3 => println!("three"),
_ => println!("anything."),
}
}
使用 ..= 來匹配字符區(qū)間
- 例子:
fn main() {
let x = 'c';
match x {
'a' ..= 'd' => println!("a | b | c | d"),
'f' ..= 'i' => println!("f | g | h | i"),
_ => println!("anything."),
}
}
使用解構來分解值(分解結構)
- 例子:
fn main() {
struct Point {
x: i32,
y: i32,
}
let point = Point {
x: 32,
y: 66
};
// 解構
let Point {x : a, y : b } = point;
println!("x:{} , y:{}", a, b);
}
稍稍復雜一點的match 匹配
- 看了這個例子突然感覺模式匹配很有用忍法,會的:
fn main() {
struct Point {
x: i32,
y: i32,
}
let point = Point {
x: 0,
y: 7
};
// 進行更復雜一點的模式匹配
match point {
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),
}
}
解構嵌套的結構體和枚舉:
- 例子:
enum Color {
Rgb (i32,i32,i32),
Hvs (i32,i32,i32),
}
enum Message {
Quit,
Write(String),
ChangeColor(Color),
}
fn main() {
let msg = Message::ChangeColor(Color::Rgb(6,6,6));
match msg {
Message::ChangeColor(Color::Rgb(r,g,b)) => {
println!("r={},g={},b={}", r,g,b);
},
Message::ChangeColor(Color::Hvs(h,v,s)) => {
println!("h={},v={},s={}", h,v,s);
},
_ => {}
}
}
使用 _ (下劃線) 忽略變量值時需要特別注意的一個問題
- 例子勉失,錯誤的
fn main() {
let s = Some(String::from("Hello."));
if let(_s) = s {
println!("Hello , into there.")
}
// 這段代碼編譯不過去,雖然 _s 但是所有權仍然會轉移
println!("s value is : {:?} ", s);
}
- 例子原探,正確的乱凿,_ 單純的下滑線就不會造成所有權轉移顽素,稍稍修改一下。
fn main() {
let s = Some(String::from("Hello."));
// 修改一下這里徒蟆,去掉 _ 后面的任何值胁出,所有權就不會轉移。
if let(_) = s {
println!("Hello , into there.")
}
println!("s value is : {:?} ", s);
}
使用 .. (雙點) 忽略匹配值
- 例子:
struct Point {
x: i32, y:i32 , z:i32,
}
fn main() {
let p = Point {x:3,y:4,z:5};
// 如果只是想匹配x 可以使用雙點語法段审。
let Point{x, ..} = p;
assert_eq!(3, x);
}
為了匹配更復雜的模式可以使用match guard
- 就是在模式匹配中新增一個 if 條件全蝶,舉例:
fn main() {
let num = Some(4);
match num {
Some(x) if x < 5 => { println!("Num {} less than five. ", x) },
Some(x) => { println!("Num is {} . ", x) },
None => {},
}
}
- 注意一個情況:
match x {
4 | 5 | 6 if y => { ... }
}
實際上等于
match x {
(4 | 5 | 6) if y => { ... }
// 而不是
4 | 5 | (6 if y) => { ... }
}
模式匹配中的綁定
- 有些范圍匹配即便成功了,我們也無法捕獲到底是什么值匹配成功的戚哎。
- 這時候就需要在匹配中綁定變量需要通過 @ 運算符裸诽。
fn main() {
enum Message {
Hello {id: i32}
}
let msg = Message::Hello {id: 5};
match msg {
// 注意這里,如果不用 id_variable@ 進行變量捕獲型凳,下面的println 就無法直到具體的值是什么丈冬。
Message::Hello {id: id_variable@ 3..=7} => {
println!("Found an id in range : {} ", id_variable);
},
Message::Hello {id:10...12} => {
println!("Found id between 10 to 12");
},
Message::Hello {id} => {
println!("Found some other id : {}", id);
},
}
}
結束
- 感謝閱讀,See you at work.