杂记rust的destructuring binding(反结构化绑定)与ownership(所有权)

起因

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函数声明顺序可以随意)

猜你喜欢

转载自www.cnblogs.com/racaljk/p/10161679.html