ошибка «значение, используемое здесь после частичного перемещения»

#rust

Вопрос:

Я пытался реализовать односвязный список, имитируя реализацию стандартного связанного списка rust, и столкнулся с ошибкой при реализации pop_front метода.

Код, который я изучал в rust, находится здесь, например:

 fn pop_front_node(amp;mut self) -> Option<Box<Node<T>>> {
    // This method takes care not to create mutable references to whole nodes,
    // to maintain validity of aliasing pointers into `element`.
    self.head.map(|node| unsafe {
        let node = Box::from_raw(node.as_ptr());     // 1.
        self.head = node.next;                       // 2.

        match self.head {
            None => self.tail = None,
            // Not creating new mutable (unique!) references overlapping `element`.
            Some(head) => (*head.as_ptr()).prev = None,
        }

        self.len -= 1;
        node                                        // 3.
    })
}
 

Насколько мне известно, node в строке 1 находится Box<Node<T>> объект, который частично перемещен ( next поле) self.head в строку 2, а затем возвращен в строке 3 в качестве целого node объекта также путем перемещения, что также должно быть перемещением после частичного перемещения и, возможно, не удалось скомпилировать? Но это должно работать так, как в стандартной библиотеке.

Код, который я писал, выглядит следующим образом и страдает от ошибки «значение, используемое после частичного перемещения». Полный фрагмент на странице playgound здесь.

 fn pop_front(amp;mut self) -> Option<Box<Node<T>>> {
    self.head.map(|node| unsafe {
        // let node = Box::from_raw(node.as_ptr());
        // let node = Box::from_raw(Box::into_raw(node));
        // let node = Box::into_raw(node);
        self.head = node.next;
        node
    })
}
 

Не мог бы кто-нибудь, пожалуйста, объяснить это и дать какие-либо решения о том, как исправить ошибку? Большое спасибо.

Комментарии:

1. Вероятно, вы могли бы реализовать необходимые функции без небезопасного кода. Я еще не пробовал внедрять связанные списки. idk, если это просто неизбежная деталь с ними, но, как правило, есть способы избежать небезопасности. Например, совместное использование ссылок на объекты обычно решается с помощью интеллектуальных указателей.

2. @Elinx head -это а NonNull<Node> , а не а Box . NonNull по сути, это необработанный изменяемый указатель (только тот, который не должен быть нулевым). Как таковой, он есть Copy (он же необработанные указатели могут быть псевдонимами), чего не происходит Box .

3. @Masklinn Спасибо , что указал на разницу между NonNull и Box , но я думаю head , что это объект типа Option<NonNull<Node> и так и есть node.next , ознакомьтесь с определением здесь , два варианта не могут Copy друг другу подходить, так что я все еще Move думаю?

4. Option<T> есть Copy , если T есть Copy : doc.rust-lang.org/std/option/enum. Опция.html#impl-Копировать

5. Обязательное чтение, если вы еще этого не сделали: Изучите Rust Со Слишком Большим Количеством Связанных Списков .