我尝试运行此代码:
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));
^
我不明白为什么我会遇到这个问题,以及我必须使用哪些来避免问题。
答案 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
。由于这些参考/解除引用操作是并列的,因此不涉及移动/复制。因此,我们获得了对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
}
}
我强烈建议阅读the official guide,它解释了所有权和借用是什么以及如何使用它们,因为这些是Rust语言的基础,为了提高Rust的效率,掌握它们非常重要。