将附加方法添加到单个链接列表

Muh*_*uhd 6 rust

我正在查看rustbyexample.com上单链表示例,我注意到实现没有append方法,所以我决定尝试实现它:

fn append(self, elem: u32) -> List {
    let mut node = &self;
    loop { 
        match *node {
            Cons(_, ref tail) => {
                node = tail;
            },
            Nil => {
                node.prepend(elem);
                break;
            },
        }
    }
    return self;
}
Run Code Online (Sandbox Code Playgroud)

以上是许多不同尝试之一,但我似乎无法找到一种方法迭代到尾部并修改它,然后以某种方式返回头部,而不会以某种方式扰乱借用检查器.

我试图找出一种解决方案,不涉及复制数据或在append方法之外进行额外的簿记.

She*_*ter 7

如在迭代递归结构时无法获取可变引用:不能一次多次借用可变引用,您需要在执行迭代时转移可变引用的所有权.这需要确保您永远不会有两个对同一事物的可变引用.

我们使用与Q&A类似的代码来获取对最后一个项目(back)的可变引用,该项目始终是Nil变体.然后我们调用它并将该项设置Nil为a Cons.我们使用by-value函数包装所有这些,因为这是API想要的.

没有额外的分配,没有堆栈帧耗尽的风险.

use List::*;

#[derive(Debug)]
enum List {
    Cons(u32, Box<List>),
    Nil,
}

impl List {
    fn back(&mut self) -> &mut List {
        let mut node = self;

        loop {
            match {node} {
                &mut Cons(_, ref mut next) => node = next,
                other => return other,
            }
        }
    }

    fn append_ref(&mut self, elem: u32) {        
        *self.back() = Cons(elem, Box::new(Nil));
    }

    fn append(mut self, elem: u32) -> Self {
        self.append_ref(elem);
        self
    }
}

fn main() {
    let n = Nil;
    let n = n.append(1);
    println!("{:?}", n);
    let n = n.append(2);
    println!("{:?}", n);
    let n = n.append(3);
    println!("{:?}", n);
}
Run Code Online (Sandbox Code Playgroud)

当启用非词法生命周期时,此功能可以更明显:

fn back(&mut self) -> &mut List {
    let mut node = self;

    while let Cons(_, next) = node {
        node = next;
    }

    node
}
Run Code Online (Sandbox Code Playgroud)

  • 我看到,使用`match node`执行简单的借用,而`match {node }`强制移动. (2认同)