Matches literals
Pattern matching can directly match literal values, for example:
fn main() {
let x = 1;
match x {
1 => println!("one"),
2 => println!("two"),
3 => println!("three"),
_ => println!("anything"),
}
}
Matches a named variable
A named variable is an irrefutable pattern that can match any value, for example:
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);
}
Run output:
Matched, y = 5
at the end: x = Some(5), y = 10
Because the y in the pattern match is out of scope after the pattern match, the y printed later is the outer y.
Multiple matches
In match expressions, using |(or) syntax, you can match multiple patterns, such as:
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"),
}
}
use.. = to match a range of values
example:
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"),
}
}
Deconstruct to decompose values
You can use patterns to deconstruct structs, enumerations, tuples, and thus refer to different parts of these type values. example:
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也随意的情况
}
}
Deconstruct enumerations
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
)
}
}
}
Deconstruct nested structs and enumerations
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
)
}
_ => (),
}
}
Deconstruct structs and enumerations
struct Point {
x: i32,
y: i32,
}
fn main() {
let ((feet, inches), Point { x, y }) = ((3, 10), Point { x: 3, y: -10 });
}
Values are ignored in the pattern
There are several ways to omit an entire or partial value in a pattern match:
- _
- _ Works with other modes
- Use a name that begins with _
- .. Ignores the rest of the value
fn foo(_: i32, y: i32) {//忽略整个值
println!("This code only uses the y parameter: {}", y);
}
fn main() {
foo(3, 4);
}
In most cases, when you no longer need a particular function argument, it is best to modify the signature to no longer contain useless arguments. Ignoring function arguments can become particularly useful in some cases, such as when implementing traits, when you need a specific type signature but the function implementation doesn't need a certain argument. The compiler does not warn of the existence of unused function parameters, as if using named parameters.
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;//没有_,并且未使用的变量会被编译器警告
}
Note that using only _ and using names that begin with an underscore is a subtle difference: for example, _x will still bind the value to the variable, while _ will not bind at all.
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)
},
}
}
Use Match Guards to provide additional conditions
Match guard is an additional if condition after the match branch, which must also be met if the match is successful. Match guard adapts to more complex scenarios than separate patterns, for example:
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"),
}
}
@Bind
The @ symbol allows us to create a variable that can hold a value while testing whether it matches a pattern. example:
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)
}
}
}