简体   繁体   English

`由于需求冲突,无法为 autoref 推断适当的生命周期`,但由于特征定义约束,无法更改任何内容

[英]`cannot infer an appropriate lifetime for autoref due to conflicting requirements` but can't change anything due to trait definition constraints

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:在尝试实现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
        })
    }
}

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 . 由于需求冲突,我查看了无法推断 autoref 的适当生命周期

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 ie <'b: 'a> but I can't figure out how to do it.我的想法是,基本上我需要 state 以某种方式生命'b'a寿命更长,即<'b: 'a>但我不知道该怎么做。 Also, I have similar functions to implement iter() which works fine.此外,我有类似的功能来实现iter()效果很好。 It confuses me why iter_mut() produces such errors.它让我感到困惑为什么iter_mut()会产生这样的错误。

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> .关键是您需要能够以某种方式从 a &'b mut IterMut<'a, T>中提取Option<&'a mut 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.要了解为什么IterMut<'a, T>:= &'a mut Link<T>不能工作,您需要了解使用可变引用到底可以做什么。 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> .next的主体内, self (本质上)是&'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.除非我们对T有所了解(在这种情况下我们不知道),否则根本无法从中生成&'a mut Link<T>类型的东西。 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 .关键是,如果我们能够在较短的(通用)生命周期'b中借用某些东西并返回允许在较长生命周期'a期间进行修改的东西,我们将能够使用多个较短的生命周期(比'a和非-overlapping) 以获取具有相同生命周期的多个可变引用'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.对于不可变引用,从&'b &'a T&'a T到 go 是微不足道的:只需尊重并复制不可变引用。 By contrast, mutable references don't implement Copy .相比之下,可变引用不实现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 ).因此,如果我们不能从 a &'b mut &'a mut Link<T> &'a mut Link<T>我们当然也不能从中得到Option<&'a mut T (除了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.) (请注意,我们可以生成一个&'b mut Link<T>并因此生成一个Option<'b mut T> 。这就是您的代码现在所做的。)

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> .请记住,我们的目标是能够从 a &'b mut IterMut<'a, T>生成Option<&'a mut 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.如果我们能够无条件地生成一个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
    })
}

(playground link) (游乐场链接)

The easiest way to set things up so that this all works is by transposing IterMut<'a, T> a bit.进行设置以使这一切正常进行的最简单方法是稍微转置IterMut<'a, T> 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 !现在,您将始终能够生成带有NoneIterMut<'a, T>

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

Translating next , we get 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
    })
}

More idiomatically, we can use Option::take rather than std::mem::swap (This is mentioned earlier in Too Many Linked Lists ).更惯用的是,我们可以使用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) (游乐场链接)


This actually ends up being slightly different than the implementation in Too Many Linked Lists .这实际上与Too Many Linked Lists中的实现略有不同。 That implementation removes the double indirection of &mut Box<Node<T>> and replaces it with simply &mut Node<T> .该实现删除了&mut Box<Node<T>>的双重间接,并将其替换为简单的&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 .但是,我不确定您获得了多少,因为该实现在List::iter_mutIterator::next中仍然具有双重 deref。

Rust is trying to say that you have a dangling reference. Rust 试图说你有一个悬空的参考。

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

The problem is the following definition:问题是以下定义:

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

This can't encapsulate that you will have a "empty" node meaning reached the end of the node.这不能封装您将有一个“空”节点,这意味着到达节点的末尾。

Use the structure as mentioned in the book like:使用书中提到的结构,如:

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

This ensures that you can leave None in its place when you run end of list and use take to modify the IterMut content behind the scenes.这确保了当您运行 end of list 并使用take在后台修改 IterMut 内容时,您可以将 None 保留在其位置。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 由于需求冲突,无法为 autoref 推断适当的生命周期 - Cannot infer an appropriate lifetime for autoref due to conflicting requirements Rust:由于要求冲突,无法推断 autoref 的适当生命周期 - Rust: cannot infer an appropriate lifetime for autoref due to conflicting requirements 尝试将具有生命周期的返回值设置为结构时,由于存在冲突的要求,无法推断出 autoref 的适当生命周期 - Cannot infer an appropriate lifetime for autoref due to conflicting requirements when tried to set a return value with lifetime to a struct 错误:由于需求冲突,无法推断autoref的适当生命周期[E0495] - error: cannot infer an appropriate lifetime for autoref due to conflicting requirements [E0495] Rust:错误[E0495]:由于需求冲突,无法为 autoref 推断合适的生命周期 - Rust: error[E0495]: cannot infer an appropriate lifetime for autoref due to conflicting requirements 创建引用错误的递归列表“由于要求冲突,无法推断 autoref 的适当生命周期” - Creating a recursive list of references errors with "cannot infer an appropriate lifetime for autoref due to conflicting requirements" 由于需求冲突,无法推断出合适的生命周期 - Cannot infer an appropriate lifetime due to conflicting requirements 将结构转换为具有生存期的特征得到“由于需求冲突,无法为生存期参数&#39;a&#39;推断适当的生存期” - casting struct to trait with lifetime got “cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements” 由于递归结构中的冲突要求,无法推断出适当的生命周期 - Cannot infer an appropriate lifetime due to conflicting requirements in a recursive struct 作为函数参数的闭包“由于需求冲突而无法推断出适当的寿命” - Closure as function parameter “cannot infer an appropriate lifetime due to conflicting requirements”
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM