繁体   English   中英

在实现返回可变引用的迭代器时,如何解决“无法为 autoref 推断适当的生命周期”?

[英]How can I fix “cannot infer an appropriate lifetime for autoref” when implementing an iterator that returns mutable references?

我正在尝试为一个名为Thread的链表编写一个可变迭代器,其中每个元素都实现Block

trait Block<'a> {
    fn next(&mut self) -> Option<&'a mut (dyn Block<'a> + 'a)> {
        None
    }
}

pub struct Thread<'a> {
    head: Box<dyn Block<'a> + 'a>,
}

impl<'a> Thread<'a> {
    fn iter_mut(&mut self) -> ThreadIterator<'a> {
        ThreadIterator {
            next: Some(self.head.as_mut()),
        }
    }
}

pub struct ThreadIterator<'a> {
    next: Option<&'a mut (dyn Block<'a> + 'a)>,
}

impl<'a> Iterator for ThreadIterator<'a> {
    type Item = &'a mut (dyn Block<'a> + 'a);

    fn next(&mut self) -> Option<&'a mut (dyn Block<'a> + 'a)> {
        self.next.take().map(|mut block| {
            self.next = block.next();
            block
        })
    }
}

编译这个会 output 报错:

error[E0495]: cannot infer an appropriate lifetime for autoref due to conflicting requirements
  --> src/lib.rs:14:34
   |
14 |             next: Some(self.head.as_mut()),
   |                                  ^^^^^^
   |
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 12:5...
  --> src/lib.rs:12:5
   |
12 | /     fn iter_mut(&mut self) -> ThreadIterator<'a> {
13 | |         ThreadIterator {
14 | |             next: Some(self.head.as_mut()),
15 | |         }
16 | |     }
   | |_____^
note: ...so that reference does not outlive borrowed content
  --> src/lib.rs:14:24
   |
14 |             next: Some(self.head.as_mut()),
   |                        ^^^^^^^^^
note: but, the lifetime must be valid for the lifetime `'a` as defined on the impl at 11:6...
  --> src/lib.rs:11:6
   |
11 | impl<'a> Thread<'a> {
   |      ^^
note: ...so that the types are compatible
  --> src/lib.rs:14:24
   |
14 |             next: Some(self.head.as_mut()),
   |                        ^^^^^^^^^^^^^^^^^^
   = note: expected `dyn Block<'_>`
              found `dyn Block<'a>`

这就是为什么我需要对所有Block 'a要求(他们正在借用Runtime ):

struct Runtime {}

struct ExampleBlock<'a> {
    runtime: &'a Runtime,
    next: Box<dyn Block<'a> + 'a>,
}

impl<'a> Block<'a> for ExampleBlock<'a> {
    fn next(&mut self) -> Option<&'a mut (dyn Block<'a> + 'a)> {
        Some(self.next.as_mut())
    }
}

我尝试的第一件事是从所有引用中删除可变要求。 同样的错误。

我认为错误告诉我self.head.as_mut()的寿命超过self.head ,因此我必须确保该引用的生命周期短于Thread<'a> 我以为我用'a life for ThreadIterator<'a>满足了这个要求。 换句话说,您不可能在ThreadIterator之前删除Thread ,对吗?

编辑:

我将Block更改为 struct 以简化代码,尽管我最终需要它成为一个 trait。

struct Block {}

impl<'a> Block {
    fn next(&mut self) -> Option<&'a mut Block> {
        None
    }
}

pub struct Thread {
    head: Block,
}

impl<'a> Thread {
    fn iter_mut(&mut self) -> ThreadIterator<'a> {
        ThreadIterator {
            next: Some(&mut self.head),
        }
    }
}

pub struct ThreadIterator<'a> {
    next: Option<&'a mut Block>,
}

impl<'a> Iterator for ThreadIterator<'a> {
    type Item = &'a mut Block;

    fn next(&mut self) -> Option<&'a mut Block> {
        self.next.take().map(|mut block| {
            self.next = block.next();
            block
        })
    }
}

它基于https://rust-unofficial.github.io/too-many-lists/second-iter-mut.html

`cannot infer a proper life for autoref due to conflicting requirements`但由于特征定义约束而无法更改任何内容的答案是为迭代器引入一个Option ,我已经这样做了。 可变引用上的自定义迭代器中的生命周期参数问题LinkedList 的重新实现:IterMut 未编译并没有回答我的问题,尽管我很难将我的代码连接到他们的代码。

我终于找到了一些有用的东西:

pub struct Block {}

impl<'a> Block {
    fn next(&mut self) -> Option<&'a mut Block> {
        None
    }
}

pub struct Thread {
    head: Block,
}

impl Thread {
    fn iter_mut(&mut self) -> ThreadIterator<'_> { // The lifetime here is changed
        ThreadIterator {
            next: Some(&mut self.head),
        }
    }
}

pub struct ThreadIterator<'a> {
    next: Option<&'a mut Block>,
}

impl<'a> Iterator for ThreadIterator<'a> {
    type Item = &'a mut Block;

    fn next(&mut self) -> Option<&'a mut Block> {
        self.next.take().map(|mut block| {
            self.next = block.next();
            block
        })
    }
}

我很难将其应用于原始代码,因为可能有两种不同的生命周期,一种用于迭代器,一种用于特征。

u/quixotrykd/回答:

编译器似乎在这里窒息,因为它不知道&mut selfThreadIterator的生命周期是如何关联的。 因此,它无法保证&mut self至少与ThreadIterator中的底层借用一样长。 这里查看您的代码,那将是第 12 行(请注意,我已在上面的链接中修正了您的错误)。

您需要告诉编译器 output ThreadIterator上的生命周期与输入&mut self相同(或者从技术上讲,它至少持续的时间至少一样长,尽管您很可能在这里想要相同的生命周期),否则编译器无法确保&mut self借用的“self”只要ThreadIterator的借用就一直存在。 查看此处的生命周期省略规则,我们可以看到这不适用于您的代码,因此,您需要在&mut self上手动指定生命周期(否则它会生成另一个不相关的匿名生命周期,如编译器的错误信息)。

固定代码:

pub trait Block<'a> { // Make public to resolve unrelated error
    fn next(&mut self) -> Option<&'a mut (dyn Block<'a> + 'a)> {
        None
    }
}

pub struct Thread<'a> {
    head: Box<dyn Block<'a> + 'a>,
}

impl<'a> Thread<'a> {
    fn iter_mut(&'a mut self) -> ThreadIterator<'a> { // Add lifetime to &self
        ThreadIterator {
            next: Some(self.head.as_mut()),
        }
    }
}

pub struct ThreadIterator<'a> {
    next: Option<&'a mut (dyn Block<'a> + 'a)>,
}

impl<'a> Iterator for ThreadIterator<'a> {
    type Item = &'a mut (dyn Block<'a> + 'a);

    fn next(&mut self) -> Option<&'a mut (dyn Block<'a> + 'a)> {
        self.next.take().map(|mut block| {
            self.next = block.next();
            block
        })
    }
}

暂无
暂无

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

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM