一生的迭代混乱
我是Rust的新手,目前一直在关注学习Rust完全有太多的链接列表示例。在 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
Next < /code>以这种方式,使用
as_mut
和地图
:
// function body in the fn next
self.this.as_mut().map(|node|{
self.this = &mut node.next;
&mut node.elem
})
这也触发了编译错误(不兼容的寿命)。
因此,我想知道这里发生了什么, self
in fn Next
的生命周期与 itermut
('a)相同吗?对于这种情况有什么解决方法吗?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
主要问题在于试图参考整个
head
。当该参考文献寿命时,您不能分发对其中任何东西的可变引用。不过,您只需要访问节点
head
中的。因此,首先,我们重构itermut
仅将引用保留到任何给定的节点
:现在,要将其从
head
中获取,我们使用便利方法as_deref_mut()
option
提供。它只是为我们提供了内部的任何内容(如果有的话):现在,
'a
仅与该node
息息相关,我们可以用它做我们想做的事,就像一样,请
in:我们可以使用简单的
MAP
调用:The principal problem lies in trying to take a reference to the whole
head
. While that reference lives, you can't hand out mutable references to anything inside it. You only need access to theNode
that's insidehead
, though. So first, we refactorIterMut
to only keep a reference into any givenNode
:Now, to get that out of the
head
we use the convenience methodas_deref_mut()
thatOption
provides. It just gives us a mutable reference to whatever was inside it (if anything):Now,
'a
is only tied to thatNode
and we can do what we want with it, liketake
ing it:And we can simplify that with a simple
map
call:1。复制错误msg的简单代码
,用
&amp; self
或&amp; mut self
作为输入和&amp;'作为回报值,它不是迭代器,而是具有相同的效果。
fn test_return_ref_field
是可以的,因为不变的参考为复制
类型。要重现错误消息,请更改
test_return_ref_mut_field
方法返回self.r_m_s
,错误msg看起来像:
根据错误msg,
self.r_m_s
self.r_m_s与输入参数
&amp; mut
'相同,并且毫无疑问要短于'a
。因为
self.r_m_s
是非复制类型,并且当引用后面时也无法部分移动(输入参数&amp; mut self
),因此其寿命与&amp; mut self
一样。怎么样,如果
self.r_m_s
是一种复合类型,例如&amp;'mut选项&lt; string&gt;
,例如:v
的类型是&amp; mut string
,似乎与self.r_m_s
无关,但是其推断的寿命与self.r_m_s
相同,我们将遇到同样的错误。这与问题的下一个相同。让我们使用以下示例对其进行验证:
2。不安全的修复
现在问题是返回值的寿命不等于或更长的时间或更长的寿命'a 。由于我们知道
&amp; mut string
应该在生命周期内有效'a
,让我们尝试与&amp; mut self的寿命相结合。 /代码>直接
。
2.1一次尝试
更改
test_return_ref_mut_field
方法如下:上面的代码转换
mut
*mut
mut 原始指针,然后将原始指针转换回。尽管它看起来像是本地变量
t
临时创建并返回的,但是RAW指针具有'static
寿命,但它比'a
更长明显地。对于您的代码,您可以尝试使用此
UNSAFE
在中转换
mut Node.elem
inin
some(&amp; mut node.elem)
。**注意:此不安全的修复程序将具有
多重mut引用
问题,请尝试以下示例:**但对于
itermut
,因为每次next
next 称为,self。此
将更新到下一个
节点,直到它到达none
。两次都没有机会参考相同值。2.2另一次尝试
代码,您还可以将
itermut
结构更改为:但是会导致错误,即
'未使用
,使用phantomdata保持它:<代码> fn iter_mut 应该更改为:
并在
fn Next
as中使用它:2.3使用
option&lt;&lt;' &amp;'t
其他答案中已经提到的解决方案。
选项
具有方便的采用方法,它是一个魔术函数实现,仔细使用不安全的代码,您可以将其视为官方解决方案,无法在安全下完成某些常见任务模式。请看以下示例:
1. simple codes to reproduce the error msg
Construct a function with
&self
or&mut self
as input and&'a SOMETHING
as return value, it's not an iterator but have the same effect.fn test_return_ref_field
is Ok since immutable reference isCopy
type.To reproduce the error msg, change
test_return_ref_mut_field
method to returnself.r_m_s
And the error msg looks like:
According to error msg, the lifetime of
self.r_m_s
is same as input argument&mut self
' and no doubt shorter than'a
.Because
self.r_m_s
is non-Copy type, and it also can not be partially moved out when behind a reference (the input argument&mut self
), so its lifetime is as same as&mut self
.How about if
self.r_m_s
is a compound type such as&'a mut Option<String>
, for example:The type of
v
is&mut String
, and seems nothing related toself.r_m_s
, but its inferred lifetime is same asself.r_m_s
, we will encounter the same error. And this is the same situation asfn next
of the question.Let's verify it using below example:
2. unsafe fix
Now the problem is lifetime of return value is not equal to or longer than required lifetime
'a
. Since we know&mut String
should be valid within lifetime'a
, Let's try to cut its ties with the lifetime of&mut self
directly.2.1 one try
Change
test_return_ref_mut_field
method as below:Above codes convert
&mut
to*mut
raw pointer then convert the raw pointer back.Although it looks like a local variable
t
created temporarily and returned, but raw pointer have a'static
life time, it is longer than'a
obviously.For your code, you can try this
unsafe
way to convert&mut node.elem
inSome(&mut node.elem)
.**Note: this unsafe fix will have
multiple mut reference
issue, please try below example: **But for
IterMut
, since each timenext
called,self.this
will be updated to point tonext
node until it reachNone
. there is no chance to mutable reference to same value twice.2.2 another try
For your codes, you can also change
IterMut
structure to:But it will result to an error that
'a not used
, use a phantomdata to hold it:fn iter_mut
should change to:and use it in
fn next
as:2.3 use
Option<&'a mut T>
instead of&'a mut T
This solution already mentioned in other answers.
Option
has a convenienttake
method, it is a magic function implement with unsafe codes carefully and you can treat it as a official workaround for some common tasks can not be done under safe mode.Have a look at below example: