【Rust练习】16.模式

文章题目来自:https://practice-zh.course.rs/pattern-match/patterns.html

1 🌟🌟 使用 | 可以匹配多个值, 而使用 ...= 可以匹配一个闭区间的数值序列

rust 复制代码
fn main() {}
fn match_number(n: i32) {
    match n {
        // 匹配一个单独的值
        1 => println!("One!"),
        // 使用 `|` 填空,不要使用 `..` 或 `..=`
        __ => println!("match 2 -> 5"),
        // 匹配一个闭区间的数值序列
        6..=10 => {
            println!("match 6 -> 10")
        },
        _ => {
            println!("match 11 -> +infinite")
        }
    }
}

将前面学到的模式匹配进行集合就可以了

rust 复制代码
fn match_number(n: i32) {
    match n {
        // 匹配一个单独的值
        1 => println!("One!"),
        // 使用 `|` 填空,不要使用 `..` 或 `..=`
        2 | 3 | 4 | 5 => println!("match 2 -> 5"),
        // 匹配一个闭区间的数值序列
        6..=10 => {
            println!("match 6 -> 10")
        }
        others => {
            println!("match 11 -> +infinite")
        }
    }
}

2 🌟🌟🌟 @ 操作符可以让我们将一个与模式相匹配的值绑定到新的变量上

rust 复制代码
struct Point {
    x: i32,
    y: i32,
}

fn main() {
    // 填空,让 p 匹配第二个分支
    let p = Point { x: __, y: __ };

    match p {
        Point { x, y: 0 } => println!("On the x axis at {}", x),
        // 第二个分支
        Point { x: 0..=5, y: y@ (10 | 20 | 30) } => println!("On the y axis at {}", y),
        Point { x, y } => println!("On neither axis: ({}, {})", x, y),
    }
}

这里的语法可能会让有些人非常疑惑:明明xy就在这里 ,为什么我要再给y绑定一个变量?如果你直接编译上述代码(我指的是修改了p的赋值之后),你会遇到如下错误:

y改成p.y就可以了。

我们先考虑另外一个场景:

rust 复制代码
fn age() -> u32 {
    15
}

fn main() {
    println!("Tell me what type of person you are");

    match age() {
        0 => println!("I haven't celebrated my first birthday yet"),
        1..=12 => println!("I'm a child of age 1..12"),
        13..=19 => println!("I'm a teen of age 13..19"),
        _ => println!("I'm an old person of age others"),
    }
}

一个典型的根据年龄匹配打印的函数,那如果我希望将被匹配的值,也就是age()的返回值打印出来呢?这就不太好办了。也许可以在println!里再调用一次?你知道可以这么做只是因为这里age()返回的值是固定的,如果它每次返回的值都不一样,显然不能这么做。

这时,@绑定就派上用场了。

rust 复制代码
fn main() {
    println!("Tell me what type of person you are");

    match age() {
        0 => println!("I haven't celebrated my first birthday yet"),
        n @ 1..=12 => println!("I'm a child of age {:?}", n),
        n @ 13..=19 => println!("I'm a teen of age {:?}", n),
        n => println!("I'm an old person of age {:?}", n),
    }
}

我们将被匹配的值绑定到n上,后续代码逻辑就可以使用了。

再考虑上面的例子,归根结底,每次匹配都只是将外部的变量和范围进行匹配,中间没有产生任何额外的变量 。所以如果你想使用,要么使用原始的外部变量,要么进行一个@绑定。而匹配所有值,本质上不是匹配,就是进行了一次绑定,所以绑定的值可以直接使用

3

rust 复制代码
// 修复错误
enum Message {
    Hello { id: i32 },
}

fn main() {
    let msg = Message::Hello { id: 5 };

    match msg {
        Message::Hello {
            id:  3..=7,
        } => println!("id 值的范围在 [3, 7] 之间: {}", id),
        Message::Hello { id: newid@10 | 11 | 12 } => {
            println!("id 值的范围在 [10, 12] 之间: {}", newid)
        }
        Message::Hello { id } => println!("Found some other id: {}", id),
    }
}

第一个需要用@绑定,第二个需要全部匹配(落个括号)

rust 复制代码
// 修复错误
enum Message {
    Hello { id: i32 },
}

fn main() {
    let msg = Message::Hello { id: 5 };

    match msg {
        Message::Hello {
            id:id@  3..=7,
        } => println!("id 值的范围在 [3, 7] 之间: {}", id),
        Message::Hello { id: newid@(10 | 11 | 12) } => {
            println!("id 值的范围在 [10, 12] 之间: {}", newid)
        }
        Message::Hello { id } => println!("Found some other id: {}", id),
    }
}

4 🌟🌟 匹配守卫(match guard)是一个位于 match 分支模式之后的额外 if 条件,它能为分支模式提供更进一步的匹配条件。

rust 复制代码
// 填空让代码工作,必须使用 `split`
fn main() {
    let num = Some(4);
    let split = 5;
    match num {
        Some(x) __ => assert!(x < split),
        Some(x) => assert!(x >= split),
        None => (),
    }
}

事实上就是多一个if条件,来进一步匹配而已。

rust 复制代码
fn main() {
    let num = Some(4);
    let split = 5;
    match num {
        Some(x) if x < split => assert!(x < split),
        Some(x) => assert!(x >= split),
        None => (),
    }
}

5 🌟🌟🌟 使用 ... 忽略一部分值

rust 复制代码
// 填空,让代码工作
fn main() {
    let numbers = (2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048);

    match numbers {
        __ => {
           assert_eq!(first, 2);
           assert_eq!(last, 2048);
        }
    }
}

可惜只能忽略一次

rust 复制代码
fn main() {
    let numbers = (2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048);

    match numbers {
        (first, .., last) => {
            assert_eq!(first, 2);
            assert_eq!(last, 2048);
        }
    }
}

6 🌟🌟 使用模式 &mut V 去匹配一个可变引用时,你需要格外小心,因为匹配出来的 V 是一个值,而不是可变引用

rust 复制代码
// 修复错误,尽量少地修改代码
// 不要移除任何代码行
fn main() {
    let mut v = String::from("hello,");
    let r = &mut v;

    match r {
       &mut value => value.push_str(" world!") 
    }
}

思来想去,也只有这一种改法了。

rust 复制代码
fn main() {
    let mut v = String::from("hello,");
    let r = &mut v;

    match r {
       value => value.push_str(" world!") 
    }
}

r本身就是对string的可变引用,如果想直接使用的话,没必要再引用一次。按图中的匹配,最后value会是一个不可变string,这样后面的操作就做不到了。

相关推荐
捕鲸叉23 分钟前
创建线程时传递参数给线程
开发语言·c++·算法
A charmer28 分钟前
【C++】vector 类深度解析:探索动态数组的奥秘
开发语言·c++·算法
码农小旋风28 分钟前
详解K8S--声明式API
后端
Peter_chq30 分钟前
【操作系统】基于环形队列的生产消费模型
linux·c语言·开发语言·c++·后端
Yaml41 小时前
Spring Boot 与 Vue 共筑二手书籍交易卓越平台
java·spring boot·后端·mysql·spring·vue·二手书籍
小小小妮子~1 小时前
Spring Boot详解:从入门到精通
java·spring boot·后端
hong1616881 小时前
Spring Boot中实现多数据源连接和切换的方案
java·spring boot·后端
记录成长java2 小时前
ServletContext,Cookie,HttpSession的使用
java·开发语言·servlet
前端青山2 小时前
Node.js-增强 API 安全性和性能优化
开发语言·前端·javascript·性能优化·前端框架·node.js
hikktn2 小时前
如何在 Rust 中实现内存安全:与 C/C++ 的对比分析
c语言·安全·rust