Rust 模式匹配示例

52 阅读3分钟

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);
        }
        _ => {}
    }
}