迭代器的生命周期混淆
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_mut
和map
:
// 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
相关联,我们可以用它做我们想做的事,比如 take
ing 它:
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
})
}
}
我是 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_mut
和map
:
// 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
相关联,我们可以用它做我们想做的事,比如 take
ing 它:
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
})
}
}