为什么在第一种情况下显式注释所需的生命周期,而在第二种情况下却不需要?

Why is explicitly annotating the lifetime required in the first case, but not in the second?

此处,需要为 items 显式注释 'a

struct App<'a> {
    items: StatefulList<'a, (&'a str, &'a str, usize)>,
}

impl<'a> App<'a> {
    fn new(items: &'a Vec<(&'a str, &'a str, usize)>) -> App<'a> {
        App {
            items: StatefulList::with_items(items),
        }
    }
}

然而,这里不是:

struct StatefulList<'a, T> {
    state: ListState,
    items: &'a Vec<T>,
}

impl<'a, T> StatefulList<'a, T> {
    fn with_items(items: &Vec<T>) -> StatefulList<T> {
        StatefulList {
            state: ListState::default(),
            items,
        }
    }
}

这是为什么?

目前,我认为这是因为编译器无法在第一种情况下计算出生命周期。

问题是在第二个中你没有 return 任何必须处理生命周期的东西,而是 StatefulList 的自有版本。在第一个中,它需要将生命周期与您 returning 相匹配,以确保您 return 的数据可能足够长寿。

事实上你甚至不需要一些注释,因为编译器会为你强制生命周期。

impl<'a> App<'a> {
    fn new(items: &'a Vec<(&str, &str, usize)>) -> App<'a> {
        App {
            items: StatefulList::with_items(items),
        }
    }
}

&str 需要至少活到 &'a Vec

Playground

因为这件小事:

fn with_items(items: &Vec<T>) -> StatefulList<T> {
//                                           ^ here, where did the lifetime go?

StatefulList 声明为有生命周期。但是你省略了生命周期!省略时的寿命是多少?

它是被省略的生命周期,'_,或者是“搞清楚”的生命周期。编译器通过简单的 liftime elision rules“弄清楚了”。这些规则的一部分是,当参数中只有一个生命周期时(如本例 - items: &Vec<T> 的隐式生命周期),return 类型中的生命周期全部继承它。这么写明了,签名是:

fn with_items<'b>(items: &'b Vec<T>) -> StatefulList<'b, T>

impl'a 生命周期根本没有使用 。 returned StatefulList 与参数具有相同的生命周期 - 这非常好,因为您将参数用于其 items!

另一方面,在第一种情况下,我们明确指定 impl 块的 'a 生命周期。您仍然使用该参数,因此参数的生命周期必须匹配 - 它也必须是 'a

有一个 lint 可以帮助您避免这种情况:它被称为 elided_lifetimes_in_paths,并且是 rust_2018_idioms lints 组的一部分,我强烈建议 #![forbid]ing 用于新的项目。如果你这样做,编译器会抱怨:

error: hidden lifetime parameters in types are deprecated
  --> src/lib.rs:12:51
   |
12 |     fn with_items(items: &Vec<T>) -> StatefulList<T> {
   |                                                   ^ expected named lifetime parameter
   |
note: the lint level is defined here
  --> src/lib.rs:1:11
   |
1  | #![forbid(rust_2018_idioms)]
   |           ^^^^^^^^^^^^^^^^
   = note: `#[forbid(elided_lifetimes_in_paths)]` implied by `#[forbid(rust_2018_idioms)]`
help: consider using the `'_` lifetime
   |
12 |     fn with_items(items: &Vec<T>) -> StatefulList<'_, T> {
   |                                                   +++