我通过跟踪太多的链接列表来实现链接列表。在尝试实现时iter_mut(),我自己做了并制作了以下代码:
type Link<T> = Option<Box<Node<T>>>;\n\npub struct List<T> {\n head: Link<T>,\n}\n\nstruct Node<T> {\n elem: T,\n next: Link<T>,\n}\n\nimpl<T> List<T> {\n pub fn iter_mut(&mut self) -> IterMut<T> {\n IterMut::<T>(&mut self.head)\n }\n}\n\npub struct IterMut<\'a, T>(&\'a mut Link<T>);\n\nimpl<\'a, T> Iterator for IterMut<\'a, T> {\n type Item = &\'a mut T;\n\n fn next<\'b>(&\'b mut self) -> Option<&\'a mut T> {\n self.0.as_mut().map(|node| {\n self.0 = &mut (**node).next;\n &mut (**node).elem\n })\n }\n}\nRun Code Online (Sandbox Code Playgroud)\n我要避免强制和省略,因为明确可以让我理解更多。
\nerror[E0495]: cannot infer an appropriate lifetime for autoref due to conflicting requirements\n --> src/third.rs:24:16\n |\n24 | self.0.as_mut().map(|node| {\n | ^^^^^^\n |\nnote: first, the lifetime cannot outlive the lifetime `\'b` as defined on the method body at 23:13...\n --> src/third.rs:23:13\n |\n23 | fn next<\'b>(&\'b mut self) -> Option<&\'a mut T> {\n | ^^\nnote: ...so that reference does not outlive borrowed content\n --> src/third.rs:24:9\n |\n24 | self.0.as_mut().map(|node| {\n | ^^^^^^\nnote: but, the lifetime must be valid for the lifetime `\'a` as defined on the impl at 20:6...\n --> src/third.rs:20:6\n |\n20 | impl<\'a, T> Iterator for IterMut<\'a, T> {\n | ^^\nnote: ...so that reference does not outlive borrowed content\n --> src/third.rs:25:22\n |\n25 | self.0 = &mut (**node).next;\n | ^^^^^^^^^^^^^^^^^^\n\nerror: aborting due to previous error\n\nFor more information about this error, try `rustc --explain E0495`.\nRun Code Online (Sandbox Code Playgroud)\n我查看了Cannot infer an适当的生命周期 for autoref due toconflicting requests。
\n我明白一点,但不多。我在这里面临的问题是,如果我尝试更改任何内容,则会弹出错误,指出无法匹配特征定义。
\n我的想法是,基本上我需要以某种方式声明生命周期\'b超过了\'a即<\'b : \'a>,但我不知道该怎么做。另外,我有类似的功能来实现,iter()效果很好。我很困惑为什么iter_mut()会产生这样的错误。
error[E0495]: cannot infer an appropriate lifetime for autoref due to conflicting requirements\n --> src/third.rs:24:16\n |\n24 | self.0.as_mut().map(|node| {\n | ^^^^^^\n |\nnote: first, the lifetime cannot outlive the lifetime `\'b` as defined on the method body at 23:13...\n --> src/third.rs:23:13\n |\n23 | fn next<\'b>(&\'b mut self) -> Option<&\'a mut T> {\n | ^^\nnote: ...so that reference does not outlive borrowed content\n --> src/third.rs:24:9\n |\n24 | self.0.as_mut().map(|node| {\n | ^^^^^^\nnote: but, the lifetime must be valid for the lifetime `\'a` as defined on the impl at 20:6...\n --> src/third.rs:20:6\n |\n20 | impl<\'a, T> Iterator for IterMut<\'a, T> {\n | ^^\nnote: ...so that reference does not outlive borrowed content\n --> src/third.rs:25:22\n |\n25 | self.0 = &mut (**node).next;\n | ^^^^^^^^^^^^^^^^^^\n\nerror: aborting due to previous error\n\nFor more information about this error, try `rustc --explain E0495`.\nRun Code Online (Sandbox Code Playgroud)\n\xe2\x98\x9d\xef\xb8\x8f这有效。
\n关键是您需要能够以某种方式Option<&'a mut T>从 a 中提取 an &'b mut IterMut<'a, 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);
}
Run Code Online (Sandbox Code Playgroud)
关键是,如果我们能够借用一些较短(通用)生命周期的东西'b并返回一些允许在较长生命周期内进行修改的东西'a,我们就能够使用多个短生命周期(短于并且'a不重叠)来获得多个具有相同生命周期的可变引用'a。
这也解释了为什么不可变版本有效。对于不可变引用,从 到 很简单&'b &'a T:&'a T只需遵循并复制不可变引用即可。相比之下,可变引用不实现Copy.
因此,如果我们不能&'a mut Link<T>从 a生成 a &'b mut &'a mut Link<T>,我们当然也不能Option<&'a mut T从中得到 an(除了None)。(请注意,我们可以生成 a &'b mut Link<T>,因此可以生成Option<'b mut T>。这就是您的代码现在所做的。)
那么什么有效呢?请记住,我们的目标是能够Option<&'a mut T>从 a生成&'b mut IterMut<'a, 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
})
}
Run Code Online (Sandbox Code Playgroud)
使这一切正常进行的最简单的设置方法是IterMut<'a, T>稍微转置一下。不要将可变引用放在选项外部,而是将其放在选项内部!现在您将始终能够生成IterMut<'a, T>with None!
struct IterMut<'a, T>(Option<&mut Box<Node<T>>>);
Run Code Online (Sandbox Code Playgroud)
翻译一下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
})
}
Run Code Online (Sandbox Code Playgroud)
更惯用的是,我们可以使用Option::take而不std::mem::swap(这在前面的Too Many Linked Lists中提到过)。
fn next<'b>(&'b mut self) -> Option<&'a mut T> {
self.0.take().map(|node| {
self.0 = node.next.as_mut();
&mut node.elem
})
}
Run Code Online (Sandbox Code Playgroud)
这实际上与Too Many Linked Lists中的实现略有不同。该实现删除了 的双重间接&mut Box<Node<T>>,并用简单的 代替&mut Node<T>。但是,我不确定您获得了多少收益,因为该实现在List::iter_mut和中仍然有双重解引用Iterator::next。
| 归档时间: |
|
| 查看次数: |
947 次 |
| 最近记录: |