“由于需求冲突,无法为autoref推断适当的生存时间",但由于特征定义约束,因此无法更改任何内容 [英] `cannot infer an appropriate lifetime for autoref due to conflicting requirements` but can't change anything due to trait definition constraints

查看:76
本文介绍了“由于需求冲突,无法为autoref推断适当的生存时间",但由于特征定义约束,因此无法更改任何内容的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在通过遵循 too来实现链接列表许多链接列表.当尝试实现 iter_mut()时,我自己做了,并编写了以下代码:

  type Link< T>=选项< Box<节点< T>>> ;;pub struct List< T>{头:Link< T> ;,}结构节点< T>{元素:T,下一个:Link< T> ;,}impl T列表< 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>IterMut'a,T>的迭代器{类型Item =&'a mut T;fn next<'b>(&'b mut self)->选项< a mut T>{self.0.as_mut().map(| node | {self.0 =& mut(** node).next;& mut(** node).elem})}} 

我要避免强制和省略,因为露骨让我了解更多.

错误:

 错误[E0495]:由于需求冲突,无法推断自动引用的适当生存期->src/third.rs:24:16|24 |self.0.as_mut().map(| node | {|^^^^^^|注意:首先,生命周期不能超过 23:13 方法主体上定义的生命周期b"......->src/third.rs:23:13|23 |fn next<'b>(&'b mut self)->选项< a mut T>{|^^注意:...这样引用不会超过借用的内容->src/third.rs:24:9|24 |self.0.as_mut().map(| node | {|^^^^^^注意:但是,生命周期必须对生命周期''a'有效,如在20:6的展示次数上定义的...->src/third.rs:20:6|20 |impl’a,T>IterMut'a,T>的迭代器{|^^注意:...这样引用不会超过借用的内容->src/third.rs:25:22|25 |self.0 =& mut(** node).next;|^^^^^^^^^^^^^^^^^^^错误:由于先前的错误而中止有关此错误的更多信息,请尝试使用"rustc --explain E0495". 

我查看了无法推断出由于要求相互冲突,因此autoref的使用寿命很长.

我了解一点,但了解不多.我在这里面临的问题是,如果我尝试进行任何更改,都会弹出一条错误消息,提示无法与特征定义匹配.

我的想法是,基本上我需要说一生的'b 寿命超过'a ,即<'b:'a> 但我不知道该怎么做.另外,我有类似的功能来实现 iter(),效果很好.这使我感到困惑,为什么 iter_mut()会产生此类错误.

Iter

  type Link< T>=选项< Box<节点< T>>> ;;pub struct Iter< a,T>(&'a Link< T>);impl’a,T>Iter< a,T>的迭代器{类型Item =&'a T;fn next(& mut self)->Option< Self :: Item>{self.0.as_ref().map(| node | {self.0 =&(((** node).next);&(((** node).elem)})}}impl T列表< T>{pub fn iter(& self)->Iter< T>{Iter ::< T>(& self.head)}} 

☝️这有效.

解决方案

关键是您需要能够以某种方式从&'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 {去做!()}fn do_stuff<'a>(x:&'a mut i32,y:&'a mut i32){//很多东西只有在x和y没有别名的情况下才起作用* x = 13;* y = 42;}fn main(){let mut x:& mut i32 =& mut 0;令y:& mut i32 = {令z:& mut& mut i32 =& mut x;坏(z)};//`x`和`y`是别名可变引用//,我们可以同时使用两者!do_stuff(x,y);} 

(游乐场链接)

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

这也解释了为什么不可变版本有效.对于不可变引用,将&'b&'a T 转换为&'a T 很简单:只需引用并复制不可变引用即可.相比之下,可变引用不实现 Copy .


因此,如果我们无法从&'b mut&'a mut Link< T> 生成&'a mut Link< T> ,我们当然也不能从中获得 Option<&'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> .

 //这实际上是类型检查!fn next<'b>(&'b mut self) ->选项< a mut T>{let mut temp:IterMut'a,T>= todo!();//显然这行不通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)->选项< 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)->选项< a mut T>{self.0.take().map(| node | {self.0 = node.next.as_mut();& mut node.elem})} 

(游乐场链接)


实际上,这实际上与链接列表过多中的实现略有不同.该实现消除了& mut Box< T>> 的双重间接性,并将其替换为简单的& mut Node< T> .但是,我不确定您会获得多少收益,因为该实现在 List :: iter_mut Iterator :: next 中仍然具有双重deref.

I was implementing linked lists by following along too many linked lists. When trying to implement iter_mut(), I did it myself and made the following code:

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

I am to avoiding coersions and elisions because being explicit lets me understand more.

Error:

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`.

I have looked at Cannot infer an appropriate lifetime for autoref due to conflicting requirements.

I understand a bit but not much. The problem that I am facing here is that if I try to change anything, an error pops saying that can't match the trait definition.

My thought was that basically I need to state somehow that lifetime 'b outlives 'a i.e <'b : 'a> but I can't figure out how to do it. Also, I have similar functions to implement iter() which works fine. It confuses me why iter_mut() produces such errors.

Iter

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 works.

解决方案

The key thing is that you need to be able to somehow extract an Option<&'a mut T> from a &'b mut IterMut<'a, T>.

To understand why IterMut<'a, T> := &'a mut Link<T> can't work, you need to understand what exactly you can do with a mutable reference. The answer, of course, is almost everything. You can copy data out of it, change its value, and lots of other things. The one thing you can't do is invalidate it. If you want to move the data under the mutable reference out, it has to be replaced with something of the same type (including lifetimes).

Inside the body of next, self is (essentially) &'b mut &'a mut Link<T>. Unless we know something about T (and we can't in this context), there's simply no way to produce something of type &'a mut Link<T> from this. For example, if this were possible in general, we'd be able to do

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)

The point is that if we were able to borrow something for a short (generic) lifetime 'b and return something that allowed modification during the longer lifetime 'a, we'd be able to use multiple short lifetimes (shorter than 'a and non-overlapping) to get multiple mutable references with the same lifetime 'a.

This also explains why the immutable version works. With immutable references, it's trivial to go from &'b &'a T to &'a T: just deference and copy the immutable reference. By contrast, mutable references don't implement Copy.


So if we can't produce a &'a mut Link<T> from a &'b mut &'a mut Link<T>, we certainly can't get an Option<&'a mut T out of it either (other than None). (Note that we can produce a &'b mut Link<T> and hence an Option<'b mut T>. That's what your code does right now.)

So what does work? Remember our goal is to be able to produce an Option<&'a mut T> from a &'b mut IterMut<'a, T>.

If we were able to produce a IterMut<'a, T> unconditionally, we'd be able to (temporarily) replace self with it and hence be able to directly access the IterMut<'a, T> associated to our list.

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

The easiest way to set things up so that this all works is by transposing IterMut<'a, T> a bit. Rather than having the mutable reference outside the option, make it inside! Now you'll always be able to produce an IterMut<'a, T> with None!

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

Translating next, we get

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

More idiomatically, we can use Option::take rather than std::mem::swap (This is mentioned earlier in 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)


This actually ends up being slightly different than the implementation in Too Many Linked Lists. That implementation removes the double indirection of &mut Box<Node<T>> and replaces it with simply &mut Node<T>. However, I'm not sure how much you gain since that implementation still has a double deref in List::iter_mut and Iterator::next.

这篇关于“由于需求冲突,无法为autoref推断适当的生存时间",但由于特征定义约束,因此无法更改任何内容的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆