在构建链表时如何保留对最后一个节点的可变引用?

时间:2018-03-17 14:25:06

标签: linked-list rust singly-linked-list

我尝试从Iterator实施构建单链表,保持元素的顺序。

结构定义为:

#[derive(Debug)]
struct List<T> {
    list: Node<T>,
}

type Node<T> = Option<Box<Link<T>>>;

#[derive(Debug)]
struct Link<T> {
    head: T,
    tail: Node<T>,
}

我在考虑保持对列表末尾的可变引用并在迭代时扩展它。但是,我无法弄清楚如何做到这一点。 (非工作)的想法是:

impl<T> List<T> {
    pub fn from_iterator(i: &mut Iterator<Item = T>) -> Self {
        let mut list = List { list: None };
        {
            let mut last: &mut Node<T> = &mut list.list;
            for x in i {
                let singleton = Box::new(Link {
                    head: x,
                    tail: None,
                });
                *last = Some(singleton);
                // --> I aim for something like the line below. Of course
                // 'singleton' can't be accessed at this point, but even if I
                // match on *last to retrieve it, still I couldn't figure out how
                // to properly reference the new tail.
                // last = &mut singleton.tail;
            }
        }
        list
    }
}

可以反过来构建列表然后以相同的时间复杂度反转它,但我很好奇上面的方法是否可以在Rust中使用。

2 个答案:

答案 0 :(得分:2)

Cannot obtain a mutable reference when iterating a recursive structure: cannot borrow as mutable more than once at a time所述,您可以使用{}明确转让可变引用的所有权:

impl<T> List<T> {
    pub fn from_iterator<I>(i: I) -> Self
    where
        I: IntoIterator<Item = T>,
    {
        let mut list = List { list: None };
        {
            let mut last: &mut Node<T> = &mut list.list;

            for x in i {
                let singleton = Box::new(Link {
                    head: x,
                    tail: None,
                });
                *last = Some(singleton);

                last = &mut {last}.as_mut().unwrap().tail;
            }
        }
        list
    }
}

我还删除了特征对象(&mut Iterator)以支持通用对象。这允许更优化的代码(尽管使用链表可能不值得)。

很遗憾需要unwrap。即使Link放在堆上,使地址稳定,编译器也不会执行该级别的生命周期跟踪。一个可以根据这些外部知识使用unsafe代码,但我不知道它在这里值得。

答案 1 :(得分:0)

我不确定你能在循环中做到这一点。借用检查员可能不够聪明。你可以通过递归来完成它。

impl<T> List<T> {
    pub fn from_iterator(i: &mut Iterator<Item = T>) -> Self {
        let mut list = List { list: None };
        Self::append_from_iterator(&mut list.list, i);
        list
    }
    pub fn append_from_iterator(list: &mut Node<T>, i: &mut Iterator<Item = T>) {
        match i.next() {
            Some(x) => {
                let mut singleton = Box::new(Link {
                    head: x,
                    tail: None,
                });
                Self::append_from_iterator(&mut singleton.tail, i);
                *list = Some(singleton);
            }, 
            None => (),
        }

    }
}

playground