迭代器的生命周期混淆

Lifetime Confusion for iterator

我是 Rust 的新手,目前一直在关注 Learning Rust With Entirely Too Many Linked Lists 个例子。在 IterMut 部分之前,一切对我来说都很有意义。然而,在实现 IterMut(与教程不同的方式)时,我对 Rust 中的生命周期机制感到完全困惑。情况是这样的,首先我只是定义要实现的堆栈:

pub struct List<T> {
    head: Link<T>,
}

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

struct Node<T> {
    elem: T,
    next: Link<T>,
}

好的,那么当我尝试以下列方式实现迭代器时:

pub struct IterMut<'a, T>{
    this: &'a mut Link<T>
}

impl<T> List<T> {
    pub fn iter_mut(&mut self) -> IterMut<T> {
        IterMut {
            this: &mut self.head
        }
    }
}

impl<'a, T> Iterator for IterMut<'a, T>{
    type Item = &'a mut T;
    fn next(&mut self) -> Option<Self::Item> {
        if let Some(node) = self.this {
            Some(&mut node.elem)
        } else {
            None
        }
    }
}

它不会编译,结果是:

error: lifetime may not live long enough
impl<'a, T> Iterator for IterMut<'a, T>{
    -- lifetime `'a` defined here
    type Item = &'a mut T;
    fn next(&mut self) -> Option<Self::Item> {
            - let's call the lifetime of this reference `'1`
        if let Some(node) = self.this {
            Some(&mut node.elem)
            ^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'1` must outlive `'a`

原来我是这样实现函数next的,使用as_mutmap:

// function body in the fn next
self.this.as_mut().map(|node|{
    self.this = &mut node.next;
    &mut node.elem
})

这也会触发编译错误(不兼容的生命周期)。

因此我想知道这里发生了什么,fn next 中的 self 不应该与 IterMut ('a) 具有相同的生命周期吗?这种情况有什么解决方法吗?

主要问题在于试图引用整个 head。当该引用存在时,您不能分发对其中任何内容的可变引用。不过,您只需要访问 head 内的 Node。所以首先,我们重构 IterMut 以仅保留对任何给定 Node:

的引用
pub struct IterMut<'a, T>{
    this: Option<&'a mut Node<T>>
}

现在,要从 head 中获取它,我们使用 Option 提供的便捷方法 as_deref_mut()。它只是给我们一个可变的引用,指向里面的内容(如果有的话):

impl<T> List<T> {
    pub fn iter_mut(&mut self) -> IterMut<'_, T> {
        IterMut {
            this: self.head.as_deref_mut(),
        }
    }
}

现在,'a 只与那个 Node 相关联,我们可以用它做我们想做的事,比如 takeing 它:

impl<'a, T> Iterator for IterMut<'a, T>{
    type Item = &'a mut T;
    fn next(&mut self) -> Option<Self::Item> {
        if let Some(node) = self.this.take() {
            self.this = node.next.as_deref_mut();
            Some(&mut node.elem)
        } else {
            None
        }
    }
}

我们可以通过一个简单的 map 调用来简化它:

impl<'a, T> Iterator for IterMut<'a, T>{
    type Item = &'a mut T;
    fn next(&mut self) -> Option<Self::Item> {
        self.this.take().map(|node| {
            self.this = node.next.as_deref_mut();
            &mut node.elem
        })
    }
}