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 メソッドでメンバー変数をアンラップするときに、借用したコンテンツから移動できないおよび借用したコンテンツから移動できない / 共有参照の背後から移動できないについては既に確認しました。

これらの質問の1つで受け入れられた回答で提案されているように、マッチアームを削除しnext、新しいの作成で定義しようとしましLinkedListNodeたが、同じエラーメッセージが表示されます。

リストの最後に追加するappendメソッドを正常に追加しました。LinkedListNode

4

1 に答える 1

48

所有権を譲渡しようとすると、借用したコンテンツから移動できません

大まかに言うと、これは Rust の基準に反しています。借りたものの所有権がないため、所有権を譲渡することはできません。私の車を借りて ( &Car)、道で最初に見かけた人に譲ってはいけません! これは、たとえ私があなたに私の車を貸して、あなたが変更を加えることを許可したとしても当てはまります ( &mut Car)。

head値を変更できないため、 a からまったく移動できませ&selfん。

構造体が一貫性のない状態のままになるためhead、aから移動することはできません。フィールドの 1 つに未定義の値が含まれます。これは、Rust の安全性保証の中核となる手段です。&mut selfLinkedList

一般に、構造体への変更可能な参照でフィールドの新しい値を交換するにはどうすればよいですか? の何かに従う必要があります。既存の値を置き換えます。

この場合、使用できますOption::take。これにより、変数はそのまま残り、その場で a に変更されNone、以前の値が返されます。次に、その値を使用して、リストの新しいヘッドを構築できます。

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 に答える