问题描述
我正在编写一个链接列表,以围绕Rust的生存期,所有权和引用进行讨论.我有以下代码:
I'm writing a linked list to wrap my head around Rust lifetimes, ownership and references. I have the following code:
pub struct LinkedList {
head: Option<Box<LinkedListNode>>,
}
pub struct LinkedListNode {
next: Option<Box<LinkedListNode>>,
}
impl LinkedList {
pub fn new() -> LinkedList {
LinkedList { head: None }
}
pub fn prepend_value(&mut self) {
let mut new_node = LinkedListNode { next: None };
match self.head {
Some(ref head) => new_node.next = Some(*head),
None => new_node.next = None,
};
self.head = Some(Box::new(new_node));
}
}
fn main() {}
但是我收到以下编译错误:
But I am getting the following compilation error:
error[E0507]: cannot move out of borrowed content
--> src/main.rs:18:52
|
18 | Some(ref head) => new_node.next = Some(*head),
| ^^^^^ cannot move out of borrowed content
较新版本的Rust的错误略有不同:
Newer versions of Rust have a slightly different error:
error[E0507]: cannot move out of `*head` which is behind a shared reference
--> src/main.rs:18:52
|
18 | Some(ref head) => new_node.next = Some(*head),
| ^^^^^ move occurs because `*head` has type `std::boxed::Box<LinkedListNode>`, which does not implement the `Copy` trait
我认为head
节点当前必须归链表self
所有.当我将其分配给new_node.next
时,可能会发生所有权更改.
I'm thinking that the head
node must currently be owned by self
, which is the linked list. When I assign it to new_node.next
, there is probably a change of ownership that will happen.
如果可能的话,我宁愿不克隆该值,因为这似乎很浪费.我不想在整个功能期间借用"它.我真的很想转让其所有权.
I would rather not clone the value if possible as that seems wasteful. I don't want to just "borrow" it for the duration of the function. I really want to transfer its ownership.
我该怎么做?
我已经查看过无法移出在& mut self方法中展开成员变量时和不能移出借用的内容/不能移出共享引用的后面.
我尝试按照其中一个问题的公认答案中的建议删除匹配臂,并在创建新的LinkedListNode
时定义了next
,但是得到了相同的错误消息.
I tried removing the match arm as suggested in the accepted answer in one of those questions and defining next
in the creation of the new LinkedListNode
, but I get the same error message.
我已经成功添加了append
方法,该方法需要将LinkedListNode
添加到列表的末尾.
I have successfully added an append
method which takes a LinkedListNode
to add to the end of the list.
推荐答案
从总体上讲,这对Rust来说是不合算的.您不能转让所借物品的所有权,因为您不拥有所有权.您不应该借用我的车(&Car
),然后将其交给在街上看到的第一个人!即使我借给您我的车并允许您对其进行更改(&mut Car
),这仍然是正确的.
At a high-level, this is against-the-grain for Rust. You cannot transfer ownership of something borrowed because you don't own it. You shouldn't borrow my car (&Car
) and then give it to the first person you see on the street! This is still true even if I lend you my car and allow you to make changes to it (&mut Car
).
您完全无法将head
从&self
中移出,因为您无法修改该值.
You cannot move head
out of a &self
at all because you cannot mutate the value.
您不能将head
从&mut self
中移出,因为这会使LinkedList
结构处于不一致状态-其中一个字段的值不确定.这是Rust的安全保证的核心措施.
You cannot move head
out of a &mut self
because this would leave the LinkedList
struct in an inconsistent state - one of the fields would have an undefined value. This is a core measure of Rust's safety guarantees.
通常,您需要遵循中的内容,如何在可变引用中为字段替换新值结构?替换现有值.
In general, you will need to follow something from How can I swap in a new value for a field in a mutable reference to a structure? to replace the existing value.
在这种情况下,您可以使用 Option::take
.这会将变量保留在原处,将其原位更改为None
并返回先前的值.然后,您可以使用该值建立列表的新标题:
In this case, you can use Option::take
. This will leave the variable where it is, changing it in-place to a None
and returning the previous value. You can then use that value to build the new head of the list:
pub fn prepend_value(&mut self) {
let head = self.head.take();
self.head = Some(Box::new(LinkedListNode { next: head }));
}
更通用的解决方案是获取结构的所有权而不是借用它.这使您可以做任何您想做的事情.请注意,我们采用的是self
值,而不是按引用:
A more generic solution is to take ownership of the struct instead of borrowing it. This allows you to do whatever you want to it. Note that we take self
by-value, not by-reference:
pub fn prepend_value(mut self) -> LinkedList {
self.head = Some(Box::new(LinkedListNode { next: self.head }));
self
}
这篇关于尝试转让所有权时无法移出借用的内容的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!