Rust点滴: 模式匹配中的表达式怎么写

862 阅读2分钟

在Rust中经常用到模式匹配, match表达式是模式匹配最常用的表达式.

match表达式大致分为3部分, match关键字, head表达式, match块. 这篇主要讨论head表达式怎么写.

head表达式

我们知道, Rust中的表达式只有两种: 位置表达式, 值表达式. 类似地, Rust表达式上下文也包括位置表达式上下文, 值表达式上下文. head表达式的位置属于位置表达式上下文, 可以是位置表达式或值表达式, 且表现出来的行为不同.

如果是值表达式, 则会对该表达式求值后, 将结果放到一个临时位置, 然后按照match分支的顺序, 比较是否有符合要求的分支. 第一个匹配到的分支作为模式匹配的目标分支, 刚刚创建的临时变量可以在分支内使用.

match 5+3 {
    8 => println!("equals!"),
    _ => println!("not equals!"),
}

如果head表达式是位置表达式, 则不会分配临时变量, 而是创建一个绑定, 根据类型是否实现Copy决定是复制语义还是移动语义.

let x = 1;

match x {
    1 => println!("one"),
    _ => println!("something else"),
}

这里的x是位置表达式, 因此整段代码相当于如下这样:

let x = 1;
let b = x; // 这里因为x是i32, 实现了Copy, 因此是复制语义
match b {
    1 => println!("one"),
    _ => println!("something else"),
}

如果是移动语义, 则会转移变量的所有权到match表达式, 当match表达式结束后, 变量就被销毁了.

如果不希望转移所有权, 则可以使用ref或ref mut, 声明一个引用绑定, 按引用进行匹配:

let x = 1;

match ref x {
    &1 => println!("one"),
    _ => println!("something else"),
}

这段代码相当于:

let x = 1;
let b = &x;
match b {
    &1 => println!("one"),
    _ => println!("something else"),
}

这里再提一些我自己理解起来比较困难的点: 当head表达式中匹配的是解引用表达式时, 与匹配引用实际上是等价的.

let y = match *x { 0 => "zero", _ => "some" };
let z = match x { &0 => "zero", _ => "some" };

assert_eq!(y, z);

参考资料