自定义链表的(可变)“Iterator”实现中出现生命周期错误

问题描述 投票:0回答:1

我正在按照教程 Learn Rust With Entirely Too Many Linked Lists 来学习 Rust。目的是通过实现不同级别的链表来学习 Rust 的各个方面。我坚持实现(可变的)

Iterator
特质(here)。这些是我的类型定义:

pub struct List<T> {
    head: Link<T>,
}
struct Node<T> {
    elem: T,
    next: Link<T>,
}
type Link<T> = Option<Box<Node<T>>>;

pub struct IntoIter<T>(List<T>);
pub struct Iter<'link, T>(&'link Link<T>);
pub struct IterMut<'link, T>(&'link mut Link<T>);

本教程对

Iter
IterMut
有以下定义(其他内容与上面相同):

pub struct Iter<T> {
    next: Option<&Node<T>>,
}
pub struct IterMut<'a, T> {
    next: Option<&'a mut Node<T>>,
}

因此,迭代器结构的区别在于,我不是像教程中那样存储对节点的可选(可变)引用,而是存储对链接的引用。

这是教程中

Iterator
特征的实现:

impl<T> Iterator for Iter<T> {
    type Item = &T;

    fn next(&mut self) -> Option<Self::Item> {
        self.next.map(|node| {
            self.next = node.next.map(|node| &node);
            &node.elem
        })
    }
}

impl<'a, T> Iterator for IterMut<'a, T> {
    type Item = &'a mut T;

    fn next(&mut self) -> Option<Self::Item> {
        self.next.take().map(|node| {
            self.next = node.next.as_deref_mut();
            &mut node.elem
        })
    }
}

这是我根据我的类型定义实现的

Iterator
特征:

impl<'link, T> Iterator for Iter<'link, T> {
    type Item = &'link T;

    fn next(&mut self) -> Option<&'link T> {
        self.0.as_ref().map(|boxed_node: &'link Box<Node<T>>| {
            self.0 = &boxed_node.next;
            &boxed_node.elem
        })
    }
}

impl<'link, T> Iterator for IterMut<'link, T> {
    type Item = &'link mut T;

    fn next(&mut self) -> Option<Self::Item> {
        self.0.as_mut().map(|boxed_node| {
            self.0 = &mut boxed_node.next;
            &mut boxed_node.elem
        })
    }
}

这是编译我的实现时的错误:

error: lifetime may not live long enough
  --> src/second.rs:96:9
   |
92 | impl<'link, T> Iterator for ListIterMut<'link, T> {
   |      ----- lifetime `'link` defined here
...
95 |     fn next(&mut self) -> Option<Self::Item> {
   |             - let's call the lifetime of this reference `'1`
96 |         self.0.as_mut().map(|boxed_node| {
   |         ^^^^^^^^^^^^^^^ argument requires that `'1` must outlive `'link`
   |
help: consider adding 'move' keyword before the nested closure
   |
96 |         self.0.as_mut().map(move |boxed_node| {
   |                             ++++

error[E0500]: closure requires unique access to `self.0` but it is already borrowed
  --> src/second.rs:96:29
   |
92 | impl<'link, T> Iterator for ListIterMut<'link, T> {
   |      ----- lifetime `'link` defined here
...
96 |         self.0.as_mut().map(|boxed_node| {
   |         ---------------     ^^^^^^^^^^^^ closure construction occurs here
   |         |
   |         borrow occurs here
   |         argument requires that `*self.0` is borrowed for `'link`
97 |             self.0 = &mut boxed_node.next;
   |             ------ second borrow occurs due to use of `self.0` in closure

如果我将我的实现与教程的实现进行比较,那么我想我缺少的是用于可变引用的

Option::take
版本。我什至不确定这样的事情是否存在。这是我的疑问:

  1. 是否存在用于可变引用的
    Option::take
    版本?
  2. 我无法理解生命周期错误。
  3. 如何在不更改类型定义的情况下修复我的代码(同时留在
    safe
    -land)?或者当前的类型定义没有办法做到这一点?

为了理解生命周期错误,我尝试对代码进行脱糖处理,在各处添加显式生命周期,但我仍然无法理解出了什么问题。老实说,我仍然在一生中挣扎。我想我明白了,然后有些事情让我崩溃了。

rust lifetime borrow-checker
1个回答
0
投票

这确实是问题所在。

是否存在用于可变引用的

Option::take
版本?

不,又是。不,因为“某些东西”必须保持在原位,否则恐慌可能会暴露未初始化的内存。是的,因为你可以放置其他东西(在这种情况下相当困难)或者只是以不同的方式处理恐慌

我无法理解生命周期错误。

它的本质是
&'short mut &'long mut T

(在这种情况下,

&mut self
,其中
Self = IterMut<'link, T>
只能给你
&'short mut T
,而不是
&'long mut T
。这意味着你从
next
elem
获得的参考资料没有预期的寿命。

如何在不更改类型定义的情况下修复我的代码(同时保持在安全地带)?

我将把上面提供的信息留给您。

© www.soinside.com 2019 - 2024. All rights reserved.