为什么 rust fn 返回&str不行,但stuct fn可以?

fn say() -> &str {
    "this is str"
}
// consider using the `'static` lifetime: `&'static `

但下面就可以

struct Cat {}
impl Cat {
    fn hi(&self) -> &str {
        "hi"
    }
}
阅读 2.6k
2 个回答

Rust 原本对所有引用都需要显式写明 lifetime ,后来逐渐加入了一些自动推断的规则,可以在某些地方省略 lifetime 标注。

第二个写法就是可以省略情况,因为有一个 &self 参数。补全就是这样的:

fn hi<'a>(&'a self) -> &'a str {

第一个写法现在无法自动推断,就需要自己写了。


life time elision

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

The reason this function compiles without lifetime annotations is historical: in early versions (pre-1.0) of Rust, this code wouldn’t have compiled because every reference needed an explicit lifetime. At that time, the function signature would have been written like this:

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

After writing a lot of Rust code, the Rust team found that Rust programmers were entering the same lifetime annotations over and over in particular situations. These situations were predictable and followed a few deterministic patterns. The developers programmed these patterns into the compiler’s code so the borrow checker could infer the lifetimes in these situations and wouldn’t need explicit annotations.
......
Lifetimes on function or method parameters are called input lifetimes, and lifetimes on return values are called output lifetimes.

The compiler uses three rules to figure out the lifetimes of the references when there aren’t explicit annotations. The first rule applies to input lifetimes, and the second and third rules apply to output lifetimes. If the compiler gets to the end of the three rules and there are still references for which it can’t figure out lifetimes, the compiler will stop with an error. These rules apply to fn definitions as well as impl blocks.

The first rule is that the compiler assigns a lifetime parameter to each parameter that’s a reference. In other words, a function with one parameter gets one lifetime parameter: fn foo<'a>(x: &'a i32); a function with two parameters gets two separate lifetime parameters: fn foo<'a, 'b>(x: &'a i32, y: &'b i32); and so on.

The second rule is that, if there is exactly one input lifetime parameter, that lifetime is assigned to all output lifetime parameters: fn foo<'a>(x: &'a i32) -> &'a i32.

The third rule is that, if there are multiple input lifetime parameters, but one of them is &self or &mut self because this is a method, the lifetime of self is assigned to all output lifetime parameters. This third rule makes methods much nicer to read and write because fewer symbols are necessary.

编译器会通过一些规则进行自动添加生命周期标注:

  • 所有引用类型的参数都有独立的生命周期
  • 如果只有一个引用类型,它的生命周期会赋给所有的输出
  • 如果有多个引用类型的参数,其实一个是self,那么它的生命周期会赋值给所有输出

你的第一个例子不满足规则,所有需要显式的生命周期标注;而第二个例子,满足规则3,所以不用进行显式标注

参考:生命周期:你创建的值究竟能活多久?

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进