web-dev-qa-db-ja.com

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

頭を包み込むようにリンクリストを書いています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メソッドを正常に追加しました。

14
Gilles

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

大まかに言えば、これはRustにとっては正反対です。借りたものを所有していないため、所有権を譲渡することはできません。私の車(&Car)を借りて、通りで最初に見た人に渡してはいけません。私があなたに私の車を貸して、あなたがそれを変更することを許可したとしても、これはまだ真実です(&mut Car)。

値を変更できないため、head&selfから移動することはできません。

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

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

この場合、 Option::take を使用できます。これにより、変数はそのままになり、その場で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
} 
30
Shepmaster