如何实现链表的前置而无需分配给新变量?

Soo*_*ner 2 move-semantics rust data-structures borrowing

有人告诉我如何实现链表:

enum List {
    Cons(u32, Box<List>),
    Nil,
}

impl List {
    fn prepend(self, elem: u32) -> List {
        Cons(elem, Box::new(self))
    }
}
Run Code Online (Sandbox Code Playgroud)

当我想使用时prepend,我需要做以下事情:

list = list.prepend(1);
Run Code Online (Sandbox Code Playgroud)

但是,我想创建一个每次prepend返回时都不需要创建新变量的函数.我只想用以下方法更改list变量本身prepend:

list.prepend(1);
Run Code Online (Sandbox Code Playgroud)

这是我提出的一个实现,但它不对:

fn my_prepend(&mut self, elem: u32) {
    *self = Cons(elem, Box::new(*self));
}
Run Code Online (Sandbox Code Playgroud)

错误是:

error[E0507]: cannot move out of borrowed content
Run Code Online (Sandbox Code Playgroud)

Pet*_*all 6

List::prepend 必须移动,self因为这实际上是发生了什么.列表的新头是一个新对象,旧头被移动到堆上,使旧变量无效.

在里面my_prepend你有一个可变引用self,但随后你移动它的值,使self引用变得无效.即使它只是暂时无效,这也是消息"cannot move out of borrowed content"抱怨的内容.

解决这个问题的一种方法是移出self变量并同时替换它Nil,以便self引用永远无效.你可以这样做mem::replace:

use std::mem;

fn my_prepend(&mut self, elem: u32) {
    // Move the value of self into head, and leave self as Nil so it isn't invalid
    let head = mem::replace(self, List::Nil);
    // Reassign to self with the prepended value
    *self = head.prepend(elem);
}
Run Code Online (Sandbox Code Playgroud)