起因
看rust by example看得我想睡觉...突然遇到个关于反结构化绑定的奇怪的特性:
struct Pair(Box<i32>, Box<i32>);
impl Pair {
fn destroy(self) {
let Pair(first, second) = self;
println!("Destroying Pair({}, {})", first, second);
}
}
fn main() {
let pair = Pair(Box::new(1), Box::new(2));
pair.destroy();
pair.destroy();
}
对pair调用两次destroy()
方法居然会得到错误,代码注释提示let
语句会消耗self,导致self内容被move(移动):
let Pair(first, second) = self;
// 这里self不再可见
以前听说过rust的lifetime
,ownership
,看着样子估计就是这方面的问题导致的特性。
尝试
我大概理解了它的行为,let
反结构化绑定有点类似于c++的std::move()
?于是做了点实验。
#[derive(Debug)]
struct A{
x:i32,
y:i32
}
impl A{
fn new()->A {
return A{x:123,y:345};
}
}
#[allow(unused_variables)]
fn main(){
let a = A::new();
let A{x:pointx,y:pointy} = a;
let A{x:pointx,y:pointy} = a;
}
很遗憾,对a执行两次反结构化绑定并没有出现内容被移动。考虑到之前Pair里面不是primitive type ,那只能试着引入非primitive type:
#[derive(Debug)]
struct A{
x:i32,
y:i32
}
struct B{
val:A
}
impl A{
fn new()->A {
return A{x:123,y:345};
}
}
#[allow(unused_variables)]
fn main(){
let a = A::new();
let A{x:pointx,y:pointy} = a;
let A{x:pointx,y:pointy} = a;
let b = B{val:a};
let B{val:res}=b;
let B{val:res}=b;
}
这次就如之前一样,对b两次反绑定得到错误,提示b.val已经被移动了。
error[E0382]: use of moved value: `b.val`
原因
然后试着rustc --explain E0382
得到了一个很长的解释:
该错误是因为尝试使用一个变量,但是变量的内容已经被移到了其他地方。
比如:
struct MyStruct { s: u32 }
fn main() {
let mut x = MyStruct{ s: 5u32 };
let y = x;
x.s = 6;
println!("{}", x.s);
}
MyStruct
是一个没有被标记为Copy的类型,当我们let y = x
时,x的数据被移了出去。
这也是Rust所有权系统的基础:一旦出了工作区,变量的值不能被两个及以上的变量拥有。
有时候我们不需要移动这个值,那么可以使用引用想另一个函数borrow(借)这个值,同时又不改变它的所有权。比如像下面这样,不需要把值移动到calculate_length
函数里面,就可以给参数加上引用:
fn main() {
let s1 = String::from("hello");
let len = calculate_length(&s1);
println!("The length of '{}' is {}.", s1, len);
}
fn calculate_length(s: &String) -> usize {
s.len()
}
(tips:rust函数声明顺序可以随意)
请发表评论