前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >杂记rust的destructuring binding(反结构化绑定)与ownership(所有权)

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

作者头像
racaljk
发布2018-12-28 15:49:19
6420
发布2018-12-28 15:49:19
举报
文章被收录于专栏:racaljkracaljk

起因

rust by example看得我想睡觉...突然遇到个关于反结构化绑定的奇怪的特性:

代码语言:javascript
复制
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(移动):

代码语言:javascript
复制
let Pair(first, second) = self;
// 这里self不再可见

以前听说过rust的lifetime,ownership,看着样子估计就是这方面的问题导致的特性

尝试

我大概理解了它的行为,let反结构化绑定有点类似于c++的std::move()?于是做了点实验。

代码语言:javascript
复制
#[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

代码语言:javascript
复制
#[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已经被移动了。

代码语言:javascript
复制
error[E0382]: use of moved value: `b.val`

原因

然后试着rustc --explain E0382得到了一个很长的解释:

该错误是因为尝试使用一个变量,但是变量的内容已经被移到了其他地方。 比如:

代码语言:javascript
复制
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函数里面,就可以给参数加上引用:

代码语言:javascript
复制
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函数声明顺序可以随意)

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2018-12-22 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 起因
  • 尝试
  • 原因
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档