Rust 所有权问题

Rust ownership issue

提问人:안태찬 提问时间:10/29/2023 最后编辑:Chayim Friedman안태찬 更新时间:10/29/2023 访问量:42

问:

我想通过 Rust 实现单链表概念。 但是,当我实现push_front功能时存在问题。

错误消息如下所示。 无法移出位于可变引用后面的 as 枚举变体self.headSome

如何解决此问题?

//! Singly linked list.
//!
//! Consult <https://doc.rust-lang.org/book/ch15-01-box.html>.

use std::fmt::Debug;

/// Node of the list.
#[derive(Debug)]
pub struct Node<T: Debug> {
    /// Value of current node.
    pub value: T,

    /// Pointer to the next node. If it is `None`, there is no next node.
    pub next: Option<Box<Node<T>>>,
}

impl<T: Debug> Node<T> {
    /// Creates a new node.
    pub fn new(value: T) -> Self {
        Self { value, next: None }
    }
}

/// A singly-linked list.
#[derive(Debug)]
pub struct SinglyLinkedList<T: Debug> {
    /// Head node of the list. If it is `None`, the list is empty.
    head: Option<Node<T>>,
}

impl<T: Debug> Default for SinglyLinkedList<T> {
    fn default() -> Self {
        Self::new()
    }
}

impl<T: Debug> SinglyLinkedList<T> {
    /// Creates a new list.
    pub fn new() -> Self {
        Self { head: None }
    }

    /// Adds the given node to the front of the list.
    pub fn push_front(&mut self, value: T) {
        let mut new_node = Node::new(value);
        new_node.next = match self.head {
            Some(head_node) => Some(Box::new(head_node)),
            None => None
        };
        self.head = Some(new_node);
    }
}
error: cannot move out of `self.head` as enum variant `Some` which is behind a mutable reference
  --> src/lib.rs:46:31
   |
46 |         new_node.next = match self.head {
   |                               ^^^^^^^^^
47 |             Some(head_node) => Some(Box::new(head_node)),
   |                  ---------
   |                  |
   |                  data moved here
   |                  move occurs because `head_node` has type `Node<T>`, which does not implement the `Copy` trait
   |
help: consider borrowing here
   |
46 |         new_node.next = match &self.head {
Rust 借用检查器 所有权

评论

1赞 Chayim Friedman 10/29/2023
我希望你不要尝试实现双链表。只是一个笔记。
1赞 Chayim Friedman 10/29/2023
吹毛求疵:在结构上设置边界几乎总是错误的。在这里,它也是不必要的限制。

答:

1赞 Chayim Friedman 10/29/2023 #1

你知道,无论如何你都会替换它,所以我们现在可以摆脱它,但编译器不知道这一点。你可以通过使用 take() 来帮助编译器:self.head

/// Adds the given node to the front of the list.
pub fn push_front(&mut self, value: T) {
    let mut new_node = Node::new(value);
    new_node.next = match self.head.take() {
        Some(head_node) => Some(Box::new(head_node)),
        None => None,
    };
    self.head = Some(new_node);
}

也可以使用 map() 缩短:match

/// Adds the given node to the front of the list.
pub fn push_front(&mut self, value: T) {
    let mut new_node = Node::new(value);
    new_node.next = self.head.take().map(Box::new);
    self.head = Some(new_node);
}

游乐场

评论

1赞 안태찬 10/29/2023
谢谢!使用地图和拍摄很棒!