你很少需要写 'a,是因为编译器有三条省略规则帮你补全。这篇把这三条规则逐条用真实代码验证,再看规则不够用时的报错,以及 '_ 这个「我知道这里有个生命周期但不想起名」的写法。
源码:
1 | fn lens(a: &str, b: &str) -> usize { a.len() + b.len() } // 省略写法
2 | fn lens_explicit<'a, 'b>(a: &'a str, b: &'b str) -> usize { a.len() + b.len() } // 等价的完整写法
3 | fn main() {
4 | let a = String::from("long lived");
5 | let r;
6 | { let b = String::from("short"); r = (lens(&a, &b), lens_explicit(&a, &b)); }
7 | println!("两种写法结果相同:{:?}", r);
8 | }
编译:成功
运行(退出码 0):
两种写法结果相同:(15, 15) 源码:
1 | fn first_char(s: &str) -> &str { &s[..1] } // 省略写法
2 | fn first_char_explicit<'a>(s: &'a str) -> &'a str { &s[..1] }
3 | fn pair(p: &(String, String)) -> (&String, &String) { (&p.0, &p.1) } // 输出有两个引用,都借自唯一的输入
4 | fn main() {
5 | let s = String::from("你好");
6 | println!("{} {}", first_char("abc"), first_char_explicit("xyz"));
7 | let t = (String::from("a"), String::from("b"));
8 | let (x, y) = pair(&t);
9 | println!("{x} {y} {}", s.len());
10 | }
编译:成功
运行(退出码 0):
a x
a b 6 源码:
1 | struct Store { name: String }
2 | impl Store {
3 | fn get(&self, other: &str) -> &str { &self.name } // 返回值借自 self
4 | fn wrong(&self, other: &str) -> &str { other } // 想返回 other:被拒绝
5 | }
6 | fn main() {}
编译:失败
warning: unused variable: `other`
--> <实验目录>/src/u27c.rs:3:19
|
3 | fn get(&self, other: &str) -> &str { &self.name } // 返回值借自 self
| ^^^^^ help: if this is intentional, prefix it with an underscore: `_other`
|
= note: `#[warn(unused_variables)]` (part of `#[warn(unused)]`) on by default
error: lifetime may not live long enough
--> <实验目录>/src/u27c.rs:4:44
|
4 | fn wrong(&self, other: &str) -> &str { other } // 想返回 other:被拒绝
| - - ^^^^^ method was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
| | |
| | let's call the lifetime of this reference `'1`
| let's call the lifetime of this reference `'2`
|
help: consider introducing a named lifetime parameter and update trait if needed
|
4 | fn wrong<'a>(&self, other: &'a str) -> &'a str { other } // 想返回 other:被拒绝
| ++++ ++ ++
error: aborting due to 1 previous error; 1 warning emitted方法里返回值借自 self 的更多场景见函数返回引用的生命周期。
源码:
1 | fn make() -> &str { "x" }
2 | fn main() {}
编译:失败
error[E0106]: missing lifetime specifier
--> <实验目录>/src/u27d.rs:1:14
|
1 | fn make() -> &str { "x" }
| ^ expected named lifetime parameter
|
= help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
help: consider using the `'static` lifetime, but this is uncommon unless you're returning a borrowed value from a `const` or a `static`
|
1 | fn make() -> &'static str { "x" }
| +++++++
help: instead, you are more likely to want to return an owned value
|
1 - fn make() -> &str { "x" }
1 + fn make() -> String { "x" }
|
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0106`.
源码:
1 | fn pick(a: &str, b: &str) -> &str { a }
2 | fn main() {}
编译:失败
error[E0106]: missing lifetime specifier
--> <实验目录>/src/u27e.rs:1:30
|
1 | fn pick(a: &str, b: &str) -> &str { a }
| ---- ---- ^ expected named lifetime parameter
|
= help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `a` or `b`
help: consider introducing a named lifetime parameter
|
1 | fn pick<'a>(a: &'a str, b: &'a str) -> &'a str { a }
| ++++ ++ ++ ++
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0106`. 源码:
1 | struct Excerpt<'a> { part: &'a str }
2 | impl Excerpt<'_> { fn len(&self) -> usize { self.part.len() } } // 不需要名字时用 '_
3 | fn show(e: &Excerpt<'_>) -> usize { e.len() }
4 | fn main() { let t = String::from("abc"); let e = Excerpt { part: &t }; println!("{}", show(&e)); }
编译:成功
运行(退出码 0):
3
编译:成功;警告:
warning: hidden lifetime parameters in types are deprecated
--> <实验目录>/src/u27g.rs:2:13
|
2 | fn show(e: &Excerpt) -> usize { e.part.len() } // 路径里藏着一个被省略的生命周期
| ^^^^^^^ expected lifetime parameter
|
= note: requested on the command line with `-W elided-lifetimes-in-paths`
help: indicate the anonymous lifetime
|
2 | fn show(e: &Excerpt<'_>) -> usize { e.part.len() } // 路径里藏着一个被省略的生命周期
| ++++
warning: 1 warning emitted
运行(退出码 0):
3