模式匹配可以直接匹配字面值,例:
fn main() {
let x = 1;
match x {
1 => println!("one"),
2 => println!("two"),
3 => println!("three"),
_ => println!("anything"),
}
}
匹配命名变量
命名变量是可匹配任何值的不可辩驳模式,例:
fn main() {
let x = Some(5);
let y = 10;
match x {
Some(50) => println!("Got 50"),
Some(y) => println!("Matched, y = {:?}", y),//Some(y)匹配的是x,即Some(5),所以此处y是5
_ => println!("Default case, x = {:?}", x),
}
println!("at the end: x = {:?}, y = {:?}", x, y);
}
运行输出:
Matched, y = 5
at the end: x = Some(5), y = 10
因为模式匹配里的y在模式匹配后已走出作用域,后面打印的y是外面的y。
多重匹配在match表达式中,使用|(或)语法,可以匹配多种模式,例:
fn main() {
let x = 1;
match x {
1 | 2 => println!("one or two"),
3 => println!("three"),
_ => println!("anything"),
}
let x = Some(5);
match x {
Some(1 | 2 | 5) => println!("here"),
_ => println!("la la la"),
}
}
使用..=来匹配某个范围的值
例:
fn main() {
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"),
}
}
解构以分解值
可以使用模式来解构结构体、枚举、元组,从而引用这些类型值的不同部分。例:
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);
assert_eq!(7, y);
match p {
Point { x, y: 0 } => println!("On the x axis at {}", x),//匹配x随意,y是0的情况
Point { x: 0, y } => println!("On the y axis at {}", y),//匹配y随意,x是0的情况
Point { x, y } => println!("On neither axis: ({}, {})", x, y),//匹配x随意,y也随意的情况
}
}
解构枚举
例:
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
)
}
}
}
解构嵌套的结构体和枚举
例:
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
)
}
_ => (),
}
}
解构结构体和枚举
例:
struct Point {
x: i32,
y: i32,
}
fn main() {
let ((feet, inches), Point { x, y }) = ((3, 10), Point { x: 3, y: -10 });
}
在模式中忽略值
有几种方式可以在模式匹配中忽略整个值或部分值:
fn foo(_: i32, y: i32) {//忽略整个值
println!("This code only uses the y parameter: {}", y);
}
fn main() {
foo(3, 4);
}
大部分情况当你不再需要特定函数参数时,最好修改签名不再包含无用的参数。在一些情况下忽略函数参数会变得特别有用,比如实现 trait 时,当你需要特定类型签名但是函数实现并不需要某个参数时。此时编译器就不会警告说存在未使用的函数参数,就跟使用命名参数一样。
fn main() {
//_忽略部分
let mut setting_value = Some(5);
let new_setting_value = Some(10);
match (setting_value, new_setting_value) {
(Some(_), Some(_)) => {
//只要求setting_value和new_setting_value都是Some即可,忽略里面的值
println!("Can't overwrite an existing customized value");
}
_ => {
setting_value = new_setting_value;
}
}
println!("setting is {:?}", setting_value);
let numbers = (2, 4, 8, 16, 32);
match numbers {
(first, _, third, _, fifth) => {
println!("Some numbers: {}, {}, {}", first, third, fifth)
}
}
}
fn main() {
let _x = 5;//_开头会忽略未使用的变量
let y = 10;//没有_,并且未使用的变量会被编译器警告
}
注意, 只使用 _ 和使用以下划线开头的名称有些微妙的不同:比如 _x 仍会将值绑定到变量,而 _ 则完全不会绑定。
fn main() {
let s = Some(String::from("Hello!"));
if let Some(_s) = s {
println!("found a string");
}
println!("{:?}", s);//编译器报错,因为_变量仍然会被绑定值,所以 s 的值会移动进 _s,这时s无法使用了。
}
fn main() {
let s = Some(String::from("Hello!"));
if let Some(_) = s {//只有下划线不会绑定值,所以通过编译
println!("found a string");
}
println!("{:?}", s);
}
fn main() {
struct Point {
x: i32,
y: i32,
z: i32,
}
let origin = Point { x: 0, y: 0, z: 0 };
//使用..忽略x以外的字段
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);
match numbers {//存在歧义,因为编译器不知道我们要的是中间的哪一个元素,所以无法编译
(.., second, ..) => {
println!("Some numbers: {}", second)
},
}
}
使用match守卫来提供额外的条件
match守卫就是match分支后额外的if条件,若想要匹配成功该条件也必须满足。match守卫适应于比单独的模式更复杂的场景,例:
fn main() {
let num = Some(4);
match num {
Some(x) if x < 5 => println!("less than five: {}", x),
Some(x) => println!("{}", x),
None => (),
}
let x = 4;
let y = false;
match x {//配合多重匹配
4 | 5 | 6 if y => println!("yes"),
_ => println!("no"),
}
}
@绑定
@符号让我们可以创建一个变量,该变量可以在测试某个值是否与模式匹配的同时保存该值。 例:
fn main() {
enum Message {
Hello { id: i32 },
}
let msg = Message::Hello { id: 5 };
match msg {
Message::Hello {
id: id_variable @ 3..=7,//要求id的值在3到7的范围时,将其值保存在id_variable中
} => {
println!("Found an id in range: {}", id_variable)
}
Message::Hello { id: 10..=12 } => {
println!("Found an id in another range")
}
Message::Hello { id } => {
println!("Found some other id: {}", id)
}
}
}
Copyright © 2024 妖气游戏网 www.17u1u.com All Rights Reserved