本文摘自《深入理解RUST标准库》,即将发售,敬请期待
对结构体引用类型“&T/&mut T"的match语法研究
如下代码:
#[derive(Debug)]
struct TestStructA {a:i32, b:i32}
fn main() {
let c = TestStructA{a:1, b:2};
match (&c) {
&e => println!("{:?}", e),
_ => println!("match nothing"),
}
}
以上代码编译时,会发生如下错误:
error[E0507]: cannot move out of a shared reference
--> src/main.rs:9:7
|
9 | match (&c) {
| ^^^^
10 | &e => println!("{:?}", e),
| --
| ||
| |data moved here
| |move occurs because `e` has type `TestStructA`, which does not implement the `Copy` trait
| help: consider removing the `&`: `e`
可见,如果match 引用类型,那对后继的pattern绑定是有讲究的。对引用做match,本意便是不想要转移所有权。因此,在match的分支中就不能有引发所有权移动的绑定出现。
再请参考如下代码:
struct TestStructA {a:i32,b:i32}
fn main() {
let a = 3;
let b = 1 + 2;
let c = TestStructA{a:1, b:2};
match (&c) {
//u实际绑定为&c.a, w实际绑定为&c.b
&TestStructA{a:ref u, b:ref w} => println!("{} {}", *u, *w),
_ => println!("match nothing"),
}
}
如果不想转移所有权,那上面代码的match就应该是一个标准的写法,对结构内部的变量也需要用ref 引用语法来绑定,尤其是结构内部变量如果没有实现Copy Trait,那就必须用引用,否则也会引发编译告警。
为了编码上的方便,RUST针对以上的代码,支持如下简化形式:
struct TestStructA {a:i32,b:i32}
fn main() {
let a = 3;
let b = 1 + 2;
let c = TestStructA{a:1, b:2};
match (&c) {
//对比上述代码,头部少了&,模式绑定内部少了 ref,但代码功能完全一致
TestStructA{a: u, b: w} => println!("{} {}", *u, *w),
_ => println!("match nothing"),
}
}
如果不知道RUST的这个实现,很可能会对这里的类型绑定感到疑惑。但从实际的使用场景分析,对结构体引用做match,其目的就是对结构体内部的成员的引用做pattern绑定。因为如果结构体内部的成员不支持Copy,是不可能对结构体成员做pattern绑定的。所以,此语法也是在RUST的所有权定义下的一个必然的简化选择。