使用生命周期参数为类型实现索引

Implementing Index for type with a lifetime parameter

我有一些这样的类型,它们每个都有一个生命周期参数。

use std::marker::PhantomData;
use std::ops::Index;

pub struct Foo<'ctx> {
    bars: Vec<Bar<'ctx>>,
    phantom: PhantomData<&'ctx ()>,
}

impl Foo<'_> {
    pub fn get_bar(&self, index: usize) -> Option<&Bar> {
        self.bars.get(index)
    }
}

pub struct Bar<'ctx> {
    // pretend we are using a context here
    phantom: PhantomData<&'ctx ()>,
}

我想为 Foo 实现 Index,但编译器不喜欢它:


impl <'ctx> Index<usize> for Foo<'ctx> {
    type Output = Bar<'ctx>;

    fn index(&self, _index: usize) -> &Self::Output {
        self.get_bar(_index).unwrap()
    }
}

我收到这个错误:

error[E0495]: cannot infer an appropriate lifetime for autoref due to conflicting requirements
  --> src/ir/foo.rs:24:14
   |
24 |         self.get_bar(_index).unwrap()
   |              ^^^^^^^
   |
note: first, the lifetime cannot outlive the anonymous lifetime defined here...
  --> src/ir/foo.rs:23:14
   |
23 |     fn index(&self, _index: usize) -> &Self::Output {
   |              ^^^^^
note: ...so that reference does not outlive borrowed content
  --> src/ir/foo.rs:24:9
   |
24 |         self.get_bar(_index).unwrap()
   |         ^^^^
note: but, the lifetime must be valid for the lifetime `'ctx` as defined here...
  --> src/ir/foo.rs:20:7
   |
20 | impl <'ctx> Index<usize> for Foo<'ctx> {
   |       ^^^^
note: ...so that the types are compatible
  --> src/ir/foo.rs:23:53
   |
23 |       fn index(&self, _index: usize) -> &Self::Output {
   |  _____________________________________________________^
24 | |         self.get_bar(_index).unwrap()
25 | |     }
   | |_____^
   = note: expected `<Foo<'ctx> as Index<usize>>`
              found `<Foo<'_> as Index<usize>>`

(我在 SO 上看到了一些类似的问题,但它们在细节上似乎都不同,即输出类型具有生命周期参数)。

这是因为当存在多个省略的生命周期时,rust 编译器无法推断出正确的生命周期。 Rust 编译器只能将省略的生命周期视为相同的生命周期 '_.

函数get_bar的推断签名实际上是:

pub fn get_bar<'_>(self: &'_ Foo<'_>, index: usize) -> Option<&'_ Bar<'_>>

注意所有的'_指的是同一个生命周期,这显然不是我们需要的,因为我们不必在整个生命周期中一直借用某些Bar的值'ctx.

并且,函数 index 的推断签名是:

fn index<'_>(self: &'_ Foo<'ctx>, _index: usize) -> &'_ Bar<'ctx>

它比 get_bar 的签名更通用,因为它允许 '_ 的生命周期参数比 'ctx 短,因此您不能在内部调用 get_bar index

的正文

要使其正常工作,您必须明确指定 'ctx,因为省略的生命周期 '_ 必须是借用的生命周期 self

impl<'ctx> Foo<'ctx> {
    pub fn get_bar(&self, index: usize) -> Option<&Bar<'ctx>> {
        self.bars.get(index)
    }
}

get_bar 的签名现在变为:

pub fn get_bar<'_>(self: &'_ Foo<'ctx>, index: usize) -> Option<&'_ Bar<'ctx>>

那么 index 中的生命周期可以匹配 get_bar

中的生命周期