为什么生存期省略不适用于返回 Fn 的函数?

Why doesn't lifetime elision work for a function that returns a Fn?

提问人:Kodra 提问时间:9/28/2023 最后编辑:Kodra 更新时间:9/28/2023 访问量:71

问:

根据 The Rust Book 的说法,生命周期省略允许我们拥有以下签名:

fn first_word(s: &str) -> &str {
...
}

而不是这个更冗长的版本:

fn first_word<'a>(s: &'a str) -> &'a str {
...
}

但后来在同一本书中,我发现我不能这样写:

fn make_a_cloner(s: &str) -> impl Fn() -> String {
  move || s.to_string()
}

我必须给返回类型一个生命周期:

fn make_a_cloner(s: &str) -> impl Fn() -> String + '_ {
...
}

我有点困惑。为什么我们在返回 a 时不需要指定任何生存期,但是当我们返回 a 时需要添加?为什么相同的省略规则不适用于这两种情况?&str'_impl Fn() -> String

防锈 瓶盖 寿命

评论


答:

6赞 kmdreko 9/28/2023 #1

尽管生命周期省略可能会让人感到困惑,但 Rust 的语法确实希望在发生借用时保持清晰。引用就是这样一个地方,它是一个明确的借用者,即使对于具有生存期的结构,也鼓励您用于参数和参数,以便生存期是显而易见的。编译器中有一个elided_lifetimes_in_paths lint 来帮助解决这个问题,但不幸的是,默认情况下是允许的;我鼓励你把它添加到你自己的代码中。MyStruct<'_>

但是,当您返回 (没有生存期) 时,没有注释来传达已发生借用。添加占位符生存期至少可以向编译器和其他开发人员传达借用正在发生。因此,如果没有生命周期注解,将默认使用,除非特征类型的其他部分传达了借用(即 将受 的约束,而不是 )。impl Trait+ '_impl Trait'staticimpl Trait<&'a T>'a'static

这不一定适用于其他地方(如函数参数)。impl Trait

评论

1赞 Kodra 9/28/2023
到目前为止,我的理解是:生命周期省略只发生在签名(而不是函数体)级别,如果我们看,就没有办法判断是否存在借用,所以省略的工作方式与我们可以判断有借用(返回)的方式不同。这是正确的吗?-> impl Fn() -> String&str
0赞 kmdreko 9/28/2023
@Kodra没错,我就是这么说的