《Rust权威指南》 第18章 模式匹配

一个模式通常由以下组件组成

  • 字面量
  • 结构的数组、枚举、结构体、元组
  • 变量
  • 通配符
  • 占位符

组件用于描述数据的形状,根据数据的形状进而对值进行匹配

所有可以使用模式的场合

match分支

match VALUE {
    PATTERN => EXPRESSION,
    PATTERN => EXPRESSION,
    PATTERN => EXPRESSION,
}

match表达式必须穷尽匹配值的所有可能性

if let 表达式

可以混合使用 if let、else if 和 else if let 表达式,提供更大的灵活性

fn main() {
    let favorite_color: Option<&str> = None;
    let is_tuesday = false;
    let age: Result<u8, _> = "34".parse();

    if let Some(color) = favorite_color {
        println!("Using your favorite color, {}, as the background", color);
    } else if is_tuesday {
        println!("Tuesday is green day!");
    } else if let Ok(age) = age {
        if age > 30 {
            println!("Using purple as the background color");
        } else {
            println!("Using orange as the background color");
        }
    } else {
        println!("Using blue as the background color");
    }
}

while let 条件循环

反复执行同一个模式匹配直到匹配失败,自动退出循环

let mut stack = Vec::new();

stack.push(1);
stack.push(2);
stack.push(3);

while let Some(top) = stack.pop() {
    println!("{}", top);
}

for 循环

for 模式 in 值(通常是一个迭代器的返回值)

例:迭代适配器enumerate会生成一个包含索引和值本身的元组

let v = vec!['a', 'b', 'c'];

for (index, value) in v.iter().enumerate() {
    println!("{} is at index {}", value, index);
}

let 语句

实际上,所有的let语句都是模式匹配

let 模式 = 表达式;

比如之前我们使用过的解构元组

let (x,y,z) = (1,2,3);

函数的参数

传参过程是模式匹配(因为传参过程类似于一个赋值过程嘛)
比如通过模式匹配解构元组实参:

fn print_coordinates(&(x, y): &(i32, i32)) {
    println!("Current location: ({}, {})", x, y);
}

fn main() {
    let point = (3, 5);
    print_coordinates(&point);
}

Refutability :模式是否会匹配失败

  • 不可失败的模式能够匹配任何传入的值
    • 函数参数、let语句、for循环只能接受不可失败模式
  • 可失败模式则可能因为某些特定的值而匹配失败
    • if let 和 while let只能接受可失败模式

模式语法

匹配字面量

匹配时要求的是“全等”

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),
        _ => println!("Default case, x = {:?}", x),
    }

    println!("at the end: x = {:?}, y = {:?}", x, y);
}

多重模式

在模式中使用|来表示“或”

let x = 1;

match x {
    1 | 2 => println!("one or two"),
    3 => println!("three"),
    _ => println!("anything"),
}

匹配区间

使用a..=b表示匹配一个a到b的闭区间,比如1..=4就等同于1|2|3|4
范围模式只被允许使用数值或者char值

使用解构来分解值

解构结构体

使用语法

结构体名 {
	字段1:模式1,
	字段2:模式2} = 结构体实例

来直接获得结构体内部的值

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: x, y: y } = p; 包含了很多重复,所以对于匹配结构体字段的模式存在简写:只需列出结构体字段的名称,则模式创建的变量会有相同的名称
fn main() {
    let p = Point { x: 0, y: 7 };

    match p {
        Point { x, y: 0 } => println!("On the x axis at {}", x),
        Point { x: 0, y } => println!("On the y axis at {}", y),
        Point { x, y } => println!("On neither axis: ({}, {})", 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
            )
        }
        _ => ()
    }
}

解构结构体和元组

let ((feet,inches),Point {x,y}) = ((3,10),Point {x:-1,y:10});

忽略模式中的值

使用_忽略整个值

比如为结构体实现trait时,trait的方法包含了不需要的参数,就用得上忽略模式了

fn foo(_: i32, y: i32) {
    println!("This code only uses the y parameter: {}", y);
}

fn main() {
    foo(3, 4);
}

使用嵌套的_忽略值的某些部分

把被忽略的部分用_补上就好

fn main() {
let numbers = (2, 4, 8, 16, 32);

match numbers {
    (first, _, third, _, fifth) => {
        println!("Some numbers: {}, {}, {}", first, third, fifth)
    },
}

通过以_开头的名称来忽略未使用的变量

如果一个变量定义了却未被使用,会触发警告
使用_开头则可以忽略未使用的变量

  • _的区别:_不会执行变量绑定,而_变量名则会执行变量绑定
let s = Some(String::from("Hello!"));

if let Some(_s) = s {
    println!("found a string");
}
//报错!
//println!("{:?}", s);
let s = Some(String::from("Hello!"));

if let Some(_) = s {
    println!("found a string");
}

println!("{:?}", s);

使用..忽略值的剩余部分

..模式可以忽略一个值中没有被我们显式匹配的部分

  • ..会自动展开并填充任意多个值

    let numbers = (2, 4, 8, 16, 32);
    
    match numbers {
        (first, .., last) => {
            println!("Some numbers: {}, {}", first, last);
        },
    }
    
  • 使用时不能出现歧义,比如下面这个例子就是有歧义

     let numbers = (2, 4, 8, 16, 32);
    
    match numbers {
        (.., second, ..) => {
    

使用匹配守卫添加额外条件

匹配守卫(match guard)是一个指定于 match 分支模式之后的额外 if 条件,它也必须被满足才能选择此分支。

let num = Some(4);

match num {
    Some(x) if x < 5 => println!("less than five: {}", x),
    Some(x) => println!("{}", x),
    None => (),
}

@绑定

运算符(@)允许我们在创建一个存放值的变量的同时测试其值是否匹配模式

enum Message {
    Hello { id: i32 },
}

let msg = Message::Hello { id: 5 };

match msg {
    Message::Hello { id: id_variable @ 3..=7 } => {
        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)
    },
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Rust权威指南是一本深入介绍Rust编程语言的权威性书籍。这本书主要介绍Rust语言的基本语法和特性,包括Rust的所有关键字、数据类型、函数、模块、宏、”生命周期”、所有权等重要概念的详细解释和使用方法。 这本书由Rust社区知名的开发者Steve Klabnik和Carol Nichols撰写,是Rust开发者及其他想要学习Rust编程语言的程序员的必读之作。书中详细介绍了Rust的语法规则和特性,如何编写高质量、高性能的Rust代码,以及如何使用Rust来进行并发编程和系统级编程。 通过阅读本书,读者能够了解Rust的核心概念,如所有权、生命周期和借用,以及如何使用Rust的工具链进行开发。在本书的后半部分,作者通过实践案例和示例向读者展示了如何使用Rust来编写高效、可靠的程序。 总的来说,Rust权威指南是一本非常实用且详尽的Rust编程语言指南,对于想要学习Rust编程语言的读者非常有益。不仅提供了基础知识方面的介绍,还给读者提供了诸如性能优化等高级内容的指导。同时,本书也适合那些已经有一定Rust编程经验的读者,它们可以通过本书深入了解Rust语言内部之间的联系。 ### 回答2: 《Rust权威指南》是一本针对Rust编程语言的详细讲解和指导的权威指南。该书由Rust的核心开发人员编写,涵盖了Rust语言的基本概念、语法、数据类型、内存管理、并发编程、错误处理、泛型、宏等方面,旨在帮助读者全面深入地学习和理解Rust语言。 该书内容广泛,详细全面,适合初学者和有经验的开发人员。书中每一都有大量的代码示例,并附有解释和注释,易于理解。书中还介绍了Rust的生态系统和常用开发工具,如包管理器Cargo、测试框架等。 此外,《Rust权威指南》还强调了Rust语言的安全性和性能优势。Rust通过静态类型检查、所有权系统、借用规则等机制,大大减少了程序运行时的内存安全问题。同时,Rust的设计和实现也使得其具有与C++类似的性能优势。 总的来说,《Rust权威指南》是一本权威性强、内容深入的Rust编程指南。对于想要学习Rust编程语言的开发人员来说,这本书绝对是一本值得购买和阅读的好书。 ### 回答3: 《Rust权威指南》是一本全面介绍Rust语言的书籍,该书由Rust中文社区的翻译小组翻译而成。这本书详细讲解了Rust语言的语法、基础知识、数据类型、控制流、函数、模块、生命周期、所有权系统等内容,涵盖了Rust语言的各个方面。 这本书的特点在于其权威性和全面性。作为Rust语言的权威指南,该书不仅涵盖了Rust语言的基础知识,还深入讲解了Rust语言的高级特性,如内存管理、安全性、并发等方面。此外,书中还包括了大量的实例和案例,可以帮助读者更深入地理解Rust语言。 对于初学者来说,该书可以作为Rust语言的入门指南。对于已经掌握了Rust语言基础知识的读者来说,本书也可以作为进一步深入学习和实践Rust语言的指南。此外,该书还提供了完整的API文档和Rust语言的标准规范,方便读者进行参考和查阅。 总之,《Rust权威指南》是一本全面、详细、权威Rust语言指南,适合Rust语言的初学者和进阶者。读者可以通过该书深入了解Rust语言并掌握其应用,提高自己的编程能力和实践经验。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值