Rust无法移出dereference指针

时间:2014-10-10 19:21:35

标签: pointers rust

我尝试运行此代码:

impl FibHeap {
fn insert(&mut self, key: int) -> () {
    let new_node = Some(box create_node(key, None, None));

        match self.min{
            Some(ref mut t) => t.right = new_node,
            None => (),
        };
        println!("{}",get_right(self.min));
    }
}
fn get_right(e: Option<Box<Node>>) -> Option<Box<Node>> {
    match e {
        Some(t) => t.right,
        None => None,
    }
}

并获得错误

error: cannot move out of dereference of `&mut`-pointer
println!("{}",get_right(self.min));
              ^

我不明白为什么我会遇到这个问题,以及我必须使用哪些来避免问题。

1 个答案:

答案 0 :(得分:10)

您的问题是get_right()接受Option<Box<Node>>,但它应该真正接受Option<&Node>并返回Option<&Node>。呼叫站点也应该适当更改。

这是解释。 Box<T>是堆分配的框。它遵循值语义(也就是说,它的行为类似于普通T,除了它具有关联的析构函数,因此它总是被移动,从不复制)。因此,只将Box<T>传递给函数意味着放弃值的所有权并将移动到函数中。但是,这不是你真正想要的,也不能在这里做。 get_right()函数仅查询现有结构,因此不需要所有权。如果不需要所有权,那么引用就是答案。此外,将self.min移动到函数中是不可能的,因为self.min是通过self访问的,这是一个借来的指针。但是,您无法从借用的数据中移出,这是编译器提供的基本安全保证之一。

get_right()定义更改为以下内容:

fn get_right(e: Option<&Node>) -> Option<&Node> {
    e.and_then(|n| n.right.as_ref().map(|r| &**r))
}

然后println!()调用应更改为:

println!("{}", get_right(self.min.map(|r| &**r))

这是这里发生的事情。要从Option<&Node>获取Option<Box<Node>>,您需要应用&#34;转换&#34;原始Option的内部。有一种方法,称为map()。但是,map()按值获取其目标,这意味着将Box<Node>移动到闭包中。但是,我们只想借用Node,因此首先我们需要从Option<Box<Node>>转到Option<&Box<Node>>才能使map()正常工作。

Option<T>有一个方法as_ref(),它通过引用获取其目标并返回Option<&T>,这是对该选项内部的可能引用。在我们的例子中,它将是Option<&Box<Node>>。现在这个值可以安全地map(),因为它包含一个引用,并且引用可以自由移动而不会影响原始值。

因此,接下来,map(|r| &**r)是从Option<&Box<Node>>Option<&Node>的转换。如果选项存在,则闭包参数将应用于选项的内部,否则None将被传递。 &**r应该从里面读出:&(*(*r)),也就是说,首先我们取消引用&Box<Node>,获取Box<Node>,然后我们取消引用后者,只获得Node,然后我们引用它,最后获得&Node。由于这些参考/解除引用操作是并列的,因此不涉及移动/复制。因此,我们获得了对NodeOption<&Node>

的可选引用

您可以在get_right()函数中看到类似的事情。但是,还有一种新方法,and_then()被调用。它等同于您最初在get_right()中编写的内容:如果其目标为None,则返回None,否则返回Option的结果 - 返回闭包传递为它的论点:

fn and_then<U>(self, f: |T| -> Option<U>) -> Option<U> {
    match self {
        Some(e) => f(e),
        None => None
    }
}

我强烈建议阅读the official guide,它解释了所有权和借用是什么以及如何使用它们,因为这些是Rust语言的基础,为了提高Rust的效率,掌握它们非常重要。