Rust无法移动解引用指针中的值

6
我会尝试翻译这段内容:

我尝试运行以下代码:

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));
              ^

我不明白为什么会出现这个问题,也不知道该如何避免。

2
我们能否拥有完整的结构体/实现块,以便我们可以编译和检查其中使用的其他方法,或者一个简化的示例(最好是可以粘贴到playpen中的)? - snf
1个回答

12
你的问题在于get_right()接受Option<Box<Node>>,而它应该接受Option<&Node>并返回Option<&Node>。调用位置也应相应更改。
这是解释。 Box<T>是一个堆分配的盒子。它遵循值语义(也就是说,它的行为类似于普通的T,只是它有关联的析构函数,因此它总是被移动,而不是复制)。因此,仅将Box<T>传递到函数中意味着放弃对该值的所有权,并将其移动到函数中。但这不是你真正想要的,也不能在这里做到。 get_right()函数仅查询现有结构,因此不需要所有权。如果不需要所有权,则引用是答案。此外,从函数移动self.min是不可能的,因为self.min通过self访问,而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<Box<Node>>中获得Option<&Node>,您需要对原始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。由于这些引用/解引用操作是并列的,因此没有涉及移动/复制。因此,我们获得了一个可选的指向Node的引用,Option<&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
    }
}

我强烈建议阅读官方指南,其中解释了什么是所有权和借用以及如何使用它们。这些是 Rust 语言的基础,掌握它们非常重要,以便在 Rust 中高效工作。请点击链接查看:官方指南

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接