Rust 模式匹配示例
Rust 中的模式匹配是一种强大的编程语言特性,它允许你根据数据的结构和属性,以一种简洁和安全的方式进行条件分支和数据解构。
元祖型模式匹配
fn main() {
assert_eq!(like(true, true), "I like money and girl".to_string());
assert_eq!(like(true, false), "I like money".to_string());
assert_eq!(like(false, true), "I like girl".to_string());
assert_eq!(like(false, false), "I like nothing".to_string());
}
fn like(money: bool, girl: bool) -> String {
match (money, girl) {
(true, true) => "I like money and girl".to_string(),
(true, false) => "I like money".to_string(),
(false, true) => "I like girl".to_string(),
(false, false) => "I like nothing".to_string(),
}
}
结构体模式匹配
struct User {
name: String,
age: u8,
active: bool,
}
fn main() {
let user = User {
name: String::from("John"),
age: 50,
active: true,
};
assert_eq!(match_user(user), "This is John , age 50, active true");
let user = User {
name: String::from("John"),
age: 40,
active: true,
};
assert_eq!(match_user(user), "This is John , age 40, active true");
let user = User {
name: String::from("John"),
age: 32,
active: true,
};
assert_eq!(match_user(user), "This is a user, age 32");
}
fn match_user(user: User) -> String {
return match user {
// 使用 .. 可以忽略其他字段
User { age: 32, .. } => { format!("This is a user, age 32") }
// 注意:不能使用 User { name: String::from("John"), age: 40, active } => {
// 原因:在模式中使用字符串字面量会导致所有权的问题
User { name: ref n, age: 40, active } if n == "John" => {
format!("This is John , age 40, active {}", active)
}
User { name, age, active } => {
format!("This is {} , age {}, active {}", name, age, active)
}
};
}
数组型模式匹配
fn main() {
let arr = [1, 2, 3];
assert_eq!(match_arr(arr), "It's match 1!");
let arr = [10, 20, 3];
assert_eq!(match_arr(arr), "It's match 2!");
let arr = [10, 2, 30];
assert_eq!(match_arr(arr), "It's match 3!");
let arr = [10, 20, 30];
assert_eq!(match_arr(arr), "none match!");
}
fn match_arr(arr: [i32; 3]) -> String {
match arr {
[1, 2, 3] => format!("It's match 1!"),
[_, _, 3] => format!("It's match 2!"),
[_, 2, _] => format!("It's match 3!"),
_ => format!("none match!"),
}
}
切片型模式匹配
fn main() {
let slice = [1, 2];
assert_eq!(match_slice(&slice), "a: 1, b: 2");
let slice = [3, 4];
assert_eq!(match_slice(&slice), "a: 3, b: 4");
let slice = [1, 2, 3, 4, 5];
assert_eq!(match_slice(&slice), "a: 1");
}
fn match_slice(slice: &[i32]) -> String {
match slice {
[a, b] => format!("a: {}, b: {}", a, b),
[a, ..] => format!("a: {}", a),
_ => format!("others"),
}
}
引用型模式匹配
错误示例:
fn match_ref(user: User) {
match user {
User { name, age } => {
println!("name: {}, age: {}", name, age);
reuse_user(user); // Value used after being moved
}
}
}
ref 模式示例:(ref 模式会借用已匹配值的一部分)
use std::fmt::format;
#[derive(Debug)]
struct User {
name: String,
age: u32,
}
fn main() {
let user = User {
name: String::from("Alice"),
age: 40,
};
assert_eq!( match_ref(user),"User { name: \"Alice Smith\", age: 40 }");
let user = User {
name: String::from("Alice"),
age: 30,
};
assert_eq!( match_ref(user),"User { name: \"Alice\", age: 30 }");
}
fn match_ref(mut user: User) -> String {
return match user {
User { ref mut name, age: 40 } => {
name.push_str(" Smith");
reuse_user(user)
}
User { ref name, age } => {
reuse_user(user)
}
};
}
fn reuse_user(user: User) -> String {
format!("{:?}", user)
}
&模式示例:(& 模式匹配引用)
use std::fmt::format;
#[derive(Debug)]
struct User {
name: String,
age: u32,
}
fn main() {
let user = User {
name: String::from("Alice"),
age: 40,
};
match_and(&user);
}
fn match_and(user: &User) {
match user {
// name 和 age 会接收副本数据,原始的 user 数据不变
&User { ref name, age } => {
println!("name: {}, age: {}", name, age);
}
}
}
// PS: 在表达式中,&会创建一个引用,在模式中,&则会匹配一个引用
守卫模式匹配
fn main() {
let v = Some(1);
match_guard(v);
}
fn match_guard(v: Option<i32>) {
match v {
None => {}
Some(x) if x > 0 => { println!("{} is positive", x); }
Some(x) => { println!("{} is negative", x); }
}
}
多种可能性模式匹配
fn main() {
match_guard(Some(0));
match_guard(Some(2));
match_guard(Some(10));
}
fn match_guard(v: Option<i32>) {
match v {
Some(0) | None => { println!("small"); }
Some(1..=5) => { println!("normal"); }
Some(_) => { println!("large"); }
}
}
@ 模式匹配
x @ pattern 会与给定的 pattern 精确匹配,讲整个值复制或移动到其中
#[derive(Debug)]
struct User {
name: String,
age: i32,
}
fn main() {
let user = User {
name: String::from("John"),
age: 32,
};
match_at(&user);
}
fn match_at(user: &User) {
match user {
u @ User { ref name, .. } if name == "John" => {
println!("Found John: {:?}", u);
}
_ => {}
}
}