如何实现链表的添加方法?

Ale*_*kiy 3 rust

我想创建一个简单的链表并在其中添加一个值.如何add实现该方法以100 50 10 5在第42行进行此代码输出,第二次root.print()调用?

use std::rc::Rc;

struct Node {
    value: i32,
    next: Option<Box<Node>>,
}

impl Node {
    fn print(&self) {
        let mut current = self;
        loop {
            println!("{}", current.value);
            match current.next {
                Some(ref next) => {
                    current = &**next;
                }
                None => break,
            }
        }
    }

    fn add(&mut self, node: Node) {
        let item = Some(Box::new(node));
        let mut current = self;
        loop {
            match current.next {
                None => current.next = item,
                _ => {} 
                //Some(next) => { current = next; }
            }
        }
    }
}

fn main() {
    let leaf = Node {
        value: 10,
        next: None,
    };
    let branch = Node {
        value: 50,
        next: Some(Box::new(leaf)),
    };
    let mut root = Node {
        value: 100,
        next: Some(Box::new(branch)),
    };
    root.print();

    let new_leaf = Node {
        value: 5,
        next: None,
    };
    root.add(new_leaf);
    root.print();
}
Run Code Online (Sandbox Code Playgroud)

(操场)

我重写了这个函数:

fn add(&mut self, node: Node) {
    let item = Some(Box::new(node));
    let mut current = self;
    loop {
        match current {
            &mut Node {
                     value: _,
                     next: None,
                 } => current.next = item,
            _ => {} 
            //Some(next) => { current = next; }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

但编译说

error[E0382]: use of moved value: `item`
  --> <anon>:28:40
   |
28 |                 None => current.next = item,
   |                                        ^^^^ value moved here in previous iteration of loop
   |
   = note: move occurs because `item` has type `std::option::Option<std::boxed::Box<Node>>`, which does not implement the `Copy` trait
Run Code Online (Sandbox Code Playgroud)

我不明白为什么它说如果项目只使用过一次之前已被移动,以及如何实现Some(_)分支以遍历列表?

blu*_*uss 5

这就是你需要写它的方式(游乐场链接)

fn add(&mut self, node: Node) {
    let item = Some(Box::new(node));
    let mut current = self;
    loop {
        match moving(current).next {
            ref mut slot @ None => {
                *slot = item;
                return;
            }
            Some(ref mut next) => current = next,
        };
    }
}
Run Code Online (Sandbox Code Playgroud)

好的,这是什么?

第1步,我们需要return在使用后立即使用该值item.然后编译器正确地看到它只从一次移动.

ref mut slot @ None => {
    *slot = item;
    return;
}
Run Code Online (Sandbox Code Playgroud)

第2步,循环使用&mut我们沿途更新的指针是棘手的.

默认情况下,生锈reborrow一个&mut被取消引用.只要借用的产品仍然存在,它就不会消耗参考,它只是考虑借用它.

显然,这在这里效果不佳.我们希望从旧current到新的"交接" current.我们可以强制&mut指针服从移动语义.

我们需要这个(identity函数强制移动!):

match moving(current).next 
Run Code Online (Sandbox Code Playgroud)

我们也可以这样写:

let tmp = current;
match tmp.next
Run Code Online (Sandbox Code Playgroud)

或这个:

match {current}.next
Run Code Online (Sandbox Code Playgroud)

第3步,我们在里面查找后没有当前指针,所以要调整代码.

  • 用于ref mut slot保持下一个值的位置.