“由于需求冲突,无法推断出 autoref 的适当生命周期”,但由于特征定义约束,无法更改任何内容
`cannot infer an appropriate lifetime for autoref due to conflicting requirements` but can't change anything due to trait definition constraints
我是按照 too many linked lists 来实现链表的。在尝试实现iter_mut()
时,我自己做了,做了如下代码:
type Link<T> = Option<Box<Node<T>>>;
pub struct List<T> {
head: Link<T>,
}
struct Node<T> {
elem: T,
next: Link<T>,
}
impl<T> List<T> {
pub fn iter_mut(&mut self) -> IterMut<T> {
IterMut::<T>(&mut self.head)
}
}
pub struct IterMut<'a, T>(&'a mut Link<T>);
impl<'a, T> Iterator for IterMut<'a, T> {
type Item = &'a mut T;
fn next<'b>(&'b mut self) -> Option<&'a mut T> {
self.0.as_mut().map(|node| {
self.0 = &mut (**node).next;
&mut (**node).elem
})
}
}
我要避免强制和省略,因为明确让我理解更多。
错误:
error[E0495]: cannot infer an appropriate lifetime for autoref due to conflicting requirements
--> src/third.rs:24:16
|
24 | self.0.as_mut().map(|node| {
| ^^^^^^
|
note: first, the lifetime cannot outlive the lifetime `'b` as defined on the method body at 23:13...
--> src/third.rs:23:13
|
23 | fn next<'b>(&'b mut self) -> Option<&'a mut T> {
| ^^
note: ...so that reference does not outlive borrowed content
--> src/third.rs:24:9
|
24 | self.0.as_mut().map(|node| {
| ^^^^^^
note: but, the lifetime must be valid for the lifetime `'a` as defined on the impl at 20:6...
--> src/third.rs:20:6
|
20 | impl<'a, T> Iterator for IterMut<'a, T> {
| ^^
note: ...so that reference does not outlive borrowed content
--> src/third.rs:25:22
|
25 | self.0 = &mut (**node).next;
| ^^^^^^^^^^^^^^^^^^
error: aborting due to previous error
For more information about this error, try `rustc --explain E0495`.
我看过。
我懂一点,但不多。我在这里面临的问题是,如果我尝试更改任何内容,则会弹出一条错误消息,指出无法匹配特征定义。
我的想法是,基本上我需要以某种方式声明生命周期 'b
比 'a
长,即 <'b : 'a>
但我不知道该怎么做。另外,我有类似的功能来实现 iter()
,效果很好。我很困惑为什么 iter_mut()
会产生这样的错误。
迭代器
type Link<T> = Option<Box<Node<T>>>;
pub struct Iter<'a, T>(&'a Link<T>);
impl<'a, T> Iterator for Iter<'a, T> {
type Item = &'a T;
fn next(&mut self) -> Option<Self::Item> {
self.0.as_ref().map(|node| {
self.0 = &((**node).next);
&((**node).elem)
})
}
}
impl<T> List<T> {
pub fn iter(&self) -> Iter<T> {
Iter::<T>(&self.head)
}
}
☝️这有效。
Rust 试图说你有一个悬空引用。
self.0.as_mut() // value borrowed
self.0 = <> // underlying value changed here.
问题是下面的定义:
pub struct IterMut<'a, T>(&'a mut Link<T>)
这无法封装您将有一个 "empty" 节点,意思是已到达节点的末尾。
使用书中提到的结构,如:
pub struct IterMut<'a, T>(Option<&'a mut Node<T>>);
这确保您可以在 运行 列表末尾时将 None 留在原处,并使用 take
在幕后修改 IterMut 内容。
关键是你需要能够以某种方式从 &'b mut IterMut<'a, T>
.
中提取 Option<&'a mut T>
要理解为什么 IterMut<'a, T> := &'a mut Link<T>
不起作用,您需要了解您可以使用可变引用做什么。答案当然是几乎所有。您可以从中复制数据、更改其值以及许多其他操作。你不能做的一件事就是使它无效。如果要将可变引用下的数据移出,则必须将其替换为相同类型(包括生命周期)的内容。
在 next
的正文中,self
(本质上)是 &'b mut &'a mut Link<T>
。除非我们知道一些关于 T
的事情(在这种情况下我们不能),否则根本没有办法从中产生 &'a mut Link<T>
类型的东西。例如,如果这在一般情况下是可能的,我们就可以做到
fn bad<'a, 'b, T>(_x: &'b mut &'a mut T) -> &'a mut T {
todo!()
}
fn do_stuff<'a>(x: &'a mut i32, y: &'a mut i32) {
// lots of stuff that only works if x and y don't alias
*x = 13;
*y = 42;
}
fn main() {
let mut x: &mut i32 = &mut 0;
let y: &mut i32 = {
let z: &mut &mut i32 = &mut x;
bad(z)
};
// `x` and `y` are aliasing mutable references
// and we can use both at once!
do_stuff(x, y);
}
关键是,如果我们能够在较短的(通用)生命周期内借用一些东西 'b
并且 return 可以在较长的生命周期内进行修改 'a
,我们' d 能够使用多个短生命周期(短于 'a
且不重叠)来获得具有相同生命周期的多个可变引用 'a
.
这也解释了为什么不可变版本有效。使用不可变引用,从 &'b &'a T
到 &'a T
是微不足道的:只需尊重并复制不可变引用。相比之下,可变引用不实现 Copy
.
所以如果我们不能从 &'b mut &'a mut Link<T>
中生成 &'a mut Link<T>
,我们当然也不能从中得到 Option<&'a mut T
(除了 None
). (请注意,我们 可以 生成 &'b mut Link<T>
,因此生成 Option<'b mut T>
。这就是您的代码现在所做的。)
那么有什么用呢?请记住,我们的目标是能够从 &'b mut IterMut<'a, T>
.
生成 Option<&'a mut T>
如果我们能够无条件地生成一个 IterMut<'a, T>
,我们就能够(暂时)用它替换 self
,因此能够直接访问 IterMut<'a, T>
关联加入我们的名单。
// This actually type-checks!
fn next<'b>(&'b mut self) -> Option<&'a mut T> {
let mut temp: IterMut<'a, T> = todo!(); // obviously this won't work
std::mem::swap(&mut self.0, &mut temp.0);
temp.0.as_mut().map(|node| {
self.0 = &mut node.next;
&mut node.elem
})
}
最简单的设置方法是稍微调换 IterMut<'a, T>
以使其正常工作。与其在选项外设置可变引用,不如在选项内设置!现在你总能用 None
!
生成 IterMut<'a, T>
struct IterMut<'a, T>(Option<&mut Box<Node<T>>>);
翻译next
,我们得到
fn next<'b>(&'b mut self) -> Option<&'a mut T> {
let mut temp: IterMut<'a, T> = IterMut(None);
std::mem::swap(&mut self.0, &mut temp.0);
temp.0.map(|node| {
self.0 = node.next.as_mut();
&mut node.elem
})
}
更惯用的是,我们可以使用Option::take
而不是std::mem::swap
(这在前面链接列表太多中提到过)。
fn next<'b>(&'b mut self) -> Option<&'a mut T> {
self.0.take().map(|node| {
self.0 = node.next.as_mut();
&mut node.elem
})
}
这实际上最终与链接列表过多中的实现略有不同。该实现删除了 &mut Box<Node<T>>
的双重间接寻址,并将其替换为简单的 &mut Node<T>
。但是,我不确定您获得了多少收益,因为该实现在 List::iter_mut
和 Iterator::next
.
中仍然有双重取消引用
我是按照 too many linked lists 来实现链表的。在尝试实现iter_mut()
时,我自己做了,做了如下代码:
type Link<T> = Option<Box<Node<T>>>;
pub struct List<T> {
head: Link<T>,
}
struct Node<T> {
elem: T,
next: Link<T>,
}
impl<T> List<T> {
pub fn iter_mut(&mut self) -> IterMut<T> {
IterMut::<T>(&mut self.head)
}
}
pub struct IterMut<'a, T>(&'a mut Link<T>);
impl<'a, T> Iterator for IterMut<'a, T> {
type Item = &'a mut T;
fn next<'b>(&'b mut self) -> Option<&'a mut T> {
self.0.as_mut().map(|node| {
self.0 = &mut (**node).next;
&mut (**node).elem
})
}
}
我要避免强制和省略,因为明确让我理解更多。
错误:
error[E0495]: cannot infer an appropriate lifetime for autoref due to conflicting requirements
--> src/third.rs:24:16
|
24 | self.0.as_mut().map(|node| {
| ^^^^^^
|
note: first, the lifetime cannot outlive the lifetime `'b` as defined on the method body at 23:13...
--> src/third.rs:23:13
|
23 | fn next<'b>(&'b mut self) -> Option<&'a mut T> {
| ^^
note: ...so that reference does not outlive borrowed content
--> src/third.rs:24:9
|
24 | self.0.as_mut().map(|node| {
| ^^^^^^
note: but, the lifetime must be valid for the lifetime `'a` as defined on the impl at 20:6...
--> src/third.rs:20:6
|
20 | impl<'a, T> Iterator for IterMut<'a, T> {
| ^^
note: ...so that reference does not outlive borrowed content
--> src/third.rs:25:22
|
25 | self.0 = &mut (**node).next;
| ^^^^^^^^^^^^^^^^^^
error: aborting due to previous error
For more information about this error, try `rustc --explain E0495`.
我看过
我懂一点,但不多。我在这里面临的问题是,如果我尝试更改任何内容,则会弹出一条错误消息,指出无法匹配特征定义。
我的想法是,基本上我需要以某种方式声明生命周期 'b
比 'a
长,即 <'b : 'a>
但我不知道该怎么做。另外,我有类似的功能来实现 iter()
,效果很好。我很困惑为什么 iter_mut()
会产生这样的错误。
迭代器
type Link<T> = Option<Box<Node<T>>>;
pub struct Iter<'a, T>(&'a Link<T>);
impl<'a, T> Iterator for Iter<'a, T> {
type Item = &'a T;
fn next(&mut self) -> Option<Self::Item> {
self.0.as_ref().map(|node| {
self.0 = &((**node).next);
&((**node).elem)
})
}
}
impl<T> List<T> {
pub fn iter(&self) -> Iter<T> {
Iter::<T>(&self.head)
}
}
☝️这有效。
Rust 试图说你有一个悬空引用。
self.0.as_mut() // value borrowed
self.0 = <> // underlying value changed here.
问题是下面的定义:
pub struct IterMut<'a, T>(&'a mut Link<T>)
这无法封装您将有一个 "empty" 节点,意思是已到达节点的末尾。
使用书中提到的结构,如:
pub struct IterMut<'a, T>(Option<&'a mut Node<T>>);
这确保您可以在 运行 列表末尾时将 None 留在原处,并使用 take
在幕后修改 IterMut 内容。
关键是你需要能够以某种方式从 &'b mut IterMut<'a, T>
.
Option<&'a mut T>
要理解为什么 IterMut<'a, T> := &'a mut Link<T>
不起作用,您需要了解您可以使用可变引用做什么。答案当然是几乎所有。您可以从中复制数据、更改其值以及许多其他操作。你不能做的一件事就是使它无效。如果要将可变引用下的数据移出,则必须将其替换为相同类型(包括生命周期)的内容。
在 next
的正文中,self
(本质上)是 &'b mut &'a mut Link<T>
。除非我们知道一些关于 T
的事情(在这种情况下我们不能),否则根本没有办法从中产生 &'a mut Link<T>
类型的东西。例如,如果这在一般情况下是可能的,我们就可以做到
fn bad<'a, 'b, T>(_x: &'b mut &'a mut T) -> &'a mut T {
todo!()
}
fn do_stuff<'a>(x: &'a mut i32, y: &'a mut i32) {
// lots of stuff that only works if x and y don't alias
*x = 13;
*y = 42;
}
fn main() {
let mut x: &mut i32 = &mut 0;
let y: &mut i32 = {
let z: &mut &mut i32 = &mut x;
bad(z)
};
// `x` and `y` are aliasing mutable references
// and we can use both at once!
do_stuff(x, y);
}
关键是,如果我们能够在较短的(通用)生命周期内借用一些东西 'b
并且 return 可以在较长的生命周期内进行修改 'a
,我们' d 能够使用多个短生命周期(短于 'a
且不重叠)来获得具有相同生命周期的多个可变引用 'a
.
这也解释了为什么不可变版本有效。使用不可变引用,从 &'b &'a T
到 &'a T
是微不足道的:只需尊重并复制不可变引用。相比之下,可变引用不实现 Copy
.
所以如果我们不能从 &'b mut &'a mut Link<T>
中生成 &'a mut Link<T>
,我们当然也不能从中得到 Option<&'a mut T
(除了 None
). (请注意,我们 可以 生成 &'b mut Link<T>
,因此生成 Option<'b mut T>
。这就是您的代码现在所做的。)
那么有什么用呢?请记住,我们的目标是能够从 &'b mut IterMut<'a, T>
.
Option<&'a mut T>
如果我们能够无条件地生成一个 IterMut<'a, T>
,我们就能够(暂时)用它替换 self
,因此能够直接访问 IterMut<'a, T>
关联加入我们的名单。
// This actually type-checks!
fn next<'b>(&'b mut self) -> Option<&'a mut T> {
let mut temp: IterMut<'a, T> = todo!(); // obviously this won't work
std::mem::swap(&mut self.0, &mut temp.0);
temp.0.as_mut().map(|node| {
self.0 = &mut node.next;
&mut node.elem
})
}
最简单的设置方法是稍微调换 IterMut<'a, T>
以使其正常工作。与其在选项外设置可变引用,不如在选项内设置!现在你总能用 None
!
IterMut<'a, T>
struct IterMut<'a, T>(Option<&mut Box<Node<T>>>);
翻译next
,我们得到
fn next<'b>(&'b mut self) -> Option<&'a mut T> {
let mut temp: IterMut<'a, T> = IterMut(None);
std::mem::swap(&mut self.0, &mut temp.0);
temp.0.map(|node| {
self.0 = node.next.as_mut();
&mut node.elem
})
}
更惯用的是,我们可以使用Option::take
而不是std::mem::swap
(这在前面链接列表太多中提到过)。
fn next<'b>(&'b mut self) -> Option<&'a mut T> {
self.0.take().map(|node| {
self.0 = node.next.as_mut();
&mut node.elem
})
}
这实际上最终与链接列表过多中的实现略有不同。该实现删除了 &mut Box<Node<T>>
的双重间接寻址,并将其替换为简单的 &mut Node<T>
。但是,我不确定您获得了多少收益,因为该实现在 List::iter_mut
和 Iterator::next
.