“由于需求冲突,无法推断 autoref 的适当生命周期”,但由于特征定义限制,无法更改任何内容

Mih*_*hir 5 lifetime rust

我通过跟踪太多的链接列表来实现链接列表。在尝试实现时iter_mut(),我自己做了并制作了以下代码:

\n
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}\n
Run Code Online (Sandbox Code Playgroud)\n

我要避免强制和省略,因为明确可以让我理解更多。

\n

错误:

\n
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`.\n
Run Code Online (Sandbox Code Playgroud)\n

我查看了Cannot infer an适当的生命周期 for autoref due toconflicting requests

\n

我明白一点,但不多。我在这里面临的问题是,如果我尝试更改任何内容,则会弹出错误,指出无法匹配特征定义。

\n

我的想法是,基本上我需要以某种方式声明生命周期\'b超过了\'a<\'b : \'a>,但我不知道该怎么做。另外,我有类似的功能来实现,iter()效果很好。我很困惑为什么iter_mut()会产生这样的错误。

\n

伊特

\n
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`.\n
Run Code Online (Sandbox Code Playgroud)\n

\xe2\x98\x9d\xef\xb8\x8f这有效。

\n

SCa*_*lla 5

关键是您需要能够以某种方式Option<&'a mut T>从 a 中提取 an &'b mut IterMut<'a, T>

要理解为什么IterMut<'a, T> := &'a mut Link<T>不起作用,您需要了解可变引用到底可以做什么。答案当然是几乎一切。您可以从中复制数据、更改其值以及执行许多其他操作。你不能做的一件事就是使其无效。如果要将可变引用下的数据移出,则必须将其替换为相同类型(包括生命周期)的数据。

在 的体内nextself(本质上)是&'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