25

我正在编写一个链表来了解 Rust 的生命周期、所有权和引用。我有以下代码:

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() {}

但我收到以下编译错误:

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 有一个稍微不同的错误:

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,可能会发生所有权变更。

如果可能的话,我宁愿不克隆该值,因为这似乎很浪费。我不想只是在函数期间“借用”它。我真的很想转让它的所有权。

我怎么做?

我已经看过在&mut self 方法中解包成员变量时无法移出借用的内容,以及无法移出借用的内容/无法移出共享引用的后面

我尝试按照其中一个问题中接受的答案中的建议删除匹配臂,并next在创建 new时进行定义LinkedListNode,但我收到了相同的错误消息。

我已成功添加了一个append方法,该方法需要将 aLinkedListNode添加到列表的末尾。

4

1 回答 1

48

尝试转移所有权时无法移出借用的内容

在高层次上,这对 Rust 来说是不合规矩的。你不能转让借来的东西的所有权,因为你不拥有它。你不应该借我的车(&Car)然后把它交给你在街上看到的第一个人!即使我将汽车借给您并允许您对其进行更改,这仍然是正确的(&mut Car)。

您根本无法移出heada &self,因为您无法改变该值。

您不能head移出 a ,&mut self因为这会使LinkedList结构处于不一致的状态 - 其中一个字段将具有未定义的值。这是 Rust 安全保证的核心衡量标准。

一般来说,您需要遵循如何在对结构的可变引用中为字段交换新值?替换现有值。

在这种情况下,您可以使用Option::take. 这会将变量保留在原处,将其原地更改为 aNone并返回先前的值。然后,您可以使用该值来构建列表的新头部:

pub fn prepend_value(&mut self) {
    let head = self.head.take();
    self.head = Some(Box::new(LinkedListNode { next: head }));
}

更通用的解决方案是获取结构的所有权而不是借用它。这使您可以为所欲为。请注意,我们采用self的是值,而不是引用:

pub fn prepend_value(mut self) -> LinkedList {
    self.head = Some(Box::new(LinkedListNode { next: self.head }));
    self
} 
于 2015-02-01T21:35:16.317 回答