【问题标题】:`cannot infer an appropriate lifetime for autoref due to conflicting requirements` but can't change anything due to trait definition constraints`由于需求冲突,无法为 autoref 推断适当的生命周期`,但由于特征定义约束,无法更改任何内容
【发布时间】:2016-05-21 02:29:04
【问题描述】:

我是按照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`.

我看过Cannot infer an appropriate lifetime for autoref due to conflicting requirements

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

我的想法是,基本上我需要以某种方式声明生命周期 'b'a 寿命更长,即 &lt;'b : 'a&gt; 但我不知道该怎么做。另外,我有类似的功能来实现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)
    }
}

☝️这行得通。

【问题讨论】:

  • 尚无答案,但这个问题与this one 几乎相同。
  • @SCappella,是的,这几乎是确切的一些问题。问题不在于编译代码。我主要对理解错误感兴趣。 @Vivek 的回答确实消除了一些疑问,并且链接问题的 cmets 也很有帮助,但仍然无法完全理解错误消息以及为什么同样适用于 iter()

标签: rust lifetime


【解决方案1】:

关键是您需要能够以某种方式从&amp;'b mut IterMut&lt;'a, T&gt; 中提取Option&lt;&amp;'a mut T&gt;

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

next 的主体内,self (本质上)是&amp;'b mut &amp;'a mut Link&lt;T&gt;。除非我们对T 有所了解(在这种情况下我们不能),否则根本无法从中产生&amp;'a mut Link&lt;T&gt; 类型的东西。例如,如果这在一般情况下是可能的,我们就能做到

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);
}

(playground link)

关键是,如果我们能够借用一些短(通用)生命周期'b 并返回允许在较长生命周期内修改的东西'a,我们将能够使用多个短生命周期(较短比'a 和非重叠)来获得多个具有相同生命周期的可变引用'a

这也解释了为什么不可变版本有效。对于不可变引用,从&amp;'b &amp;'a T&amp;'a T 是微不足道的:只需尊重并复制不可变引用。相比之下,可变引用不实现Copy


所以如果我们不能从&amp;'b mut &amp;'a mut Link&lt;T&gt; 生成&amp;'a mut Link&lt;T&gt;,我们当然也不能从中得到Option&lt;&amp;'a mut TNone 除外)。 (请注意,我们可以生成&amp;'b mut Link&lt;T&gt;,因此生成Option&lt;'b mut T&gt;。这就是您的代码现在所做的。)

那么 有什么作用呢?请记住,我们的目标是能够从 &amp;'b mut IterMut&lt;'a, T&gt; 生成 Option&lt;&amp;'a mut T&gt;

如果我们能够无条件地生成IterMut&lt;'a, T&gt;,我们将能够(暂时)用它替换self,从而能够直接访问与我们的列表关联的IterMut&lt;'a, T&gt;

// 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
    })
}

(playground link)

设置事物以使这一切正常进行的最简单方法是稍微转置IterMut&lt;'a, T&gt;。与其将可变引用放在选项之外,不如将其放在里面!现在您将始终能够使用None 生成IterMut&lt;'a, T&gt;

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(这在前面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
    })
}

(playground link)


这实际上与 Too Many Linked Lists 中的实现略有不同。该实现删除了&amp;mut Box&lt;Node&lt;T&gt;&gt; 的双重间接,并将其替换为简单的&amp;mut Node&lt;T&gt;。但是,我不确定您获得了多少,因为该实现在 List::iter_mutIterator::next 中仍然具有双重 deref。

【讨论】:

  • 这需要很长时间才能理解。超级有帮助。谢谢你治好了我两天的头痛。
  • 好吧,我现在意识到如果 trait 接受了指定 'b : 'a ('b outs a) 的想法并不是一个坏主意。如果我们将fn bad&lt;'a, 'b, T&gt;(_x: &amp;'b mut &amp;'a mut T) -&gt; &amp;'a mut T 更改为fn bad&lt;'a, 'b : 'a, T&gt;(_x: &amp;'b mut &amp;'a mut T) -&gt; &amp;'a mut T,那么编译器会接受它。你给出的例子真的很有帮助,我建议任何偶然发现这个问题的人来解决它(将 mut refs 更改为 immut refs 等)
【解决方案2】:

Rust 试图说你有一个悬空的引用。

self.0.as_mut() // value borrowed
self.0 = <> // underlying value changed here. 

问题是如下定义:

pub struct IterMut<'a,  T>(&'a mut Link<T>)

这不能封装你将有一个“空”节点,意思是到达节点的末尾。

使用书中提到的结构,如:

pub struct IterMut<'a,  T>(Option<&'a mut Node<T>>);

这确保您可以在运行 end of list 并使用 take 在后台修改 IterMut 内容时将 None 保留在其位置。

【讨论】:

  • 这对我来说很有意义。但是,iter() 怎么会起作用呢?它几乎相似。在那里我借用 as_ref() 的值,然后分配给 self.0 内部闭包,它可以正常工作而没有任何错误。你能帮我理解吗?
猜你喜欢
  • 1970-01-01
  • 2017-05-07
  • 2016-06-01
  • 2021-08-02
  • 1970-01-01
  • 1970-01-01
  • 2020-01-29
  • 2022-01-06
  • 2021-11-02
相关资源
最近更新 更多