我正在按照教程 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
版本。我什至不确定这样的事情是否存在。这是我的疑问:
Option::take
版本?safe
-land)?或者当前的类型定义没有办法做到这一点?为了理解生命周期错误,我尝试对代码进行脱糖处理,在各处添加显式生命周期,但我仍然无法理解出了什么问题。老实说,我仍然在一生中挣扎。我想我明白了,然后有些事情让我崩溃了。
这确实是问题所在。
是否存在用于可变引用的
版本?Option::take
不,又是。不,因为“某些东西”必须保持在原位,否则恐慌可能会暴露未初始化的内存。是的,因为你可以放置其他东西(在这种情况下相当困难)或者只是以不同的方式处理恐慌。
我无法理解生命周期错误。它的本质是
&'short mut &'long mut T
(在这种情况下,
&mut self
,其中Self = IterMut<'link, T>
只能给你&'short mut T
,而不是&'long mut T
。这意味着你从next
和elem
获得的参考资料没有预期的寿命。
如何在不更改类型定义的情况下修复我的代码(同时保持在安全地带)?我将把上面提供的信息留给您。