Colourful 2019-09-07
在Rust中经常用到模式匹配, match表达式是模式匹配最常用的表达式.
match表达式大致分为3部分, match关键字, head表达式, match块. 这篇主要讨论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);