如何在不需要分配新变量的情况下为链表实现前缀?

时间:2018-08-14 08:25:01

标签: data-structures rust move-semantics borrowing

某事告诉我如何实现链接列表:

InetAddress.getHostAddress()

当我想使用enum List { Cons(u32, Box<List>), Nil, } impl List { fn prepend(self, elem: u32) -> List { Cons(elem, Box::new(self)) } } 时,我需要执行以下操作:

prepend

但是,我想创建一个函数,不需要每次list = list.prepend(1); 返回时都创建一个新变量。我只想使用prepend来更改list变量本身:

prepend

这是我想出的一种实现,但这是不对的:

list.prepend(1);

错误是:

fn my_prepend(&mut self, elem: u32) {
    *self = Cons(elem, Box::new(*self));
}

1 个答案:

答案 0 :(得分: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);
}