‣
struct S<'a> {
x: &'a i32,
y: &'a i32
}
fn main() {
let x = 10;
let r;
{
let y = 20;
{
let s = S { x: &x, y: &y };
r = s.x;
}
}
println!("{} {}", x, r);
|
12 | let s = S { x: &x, y: &y };
| ^^ borrowed value does not live long enough
...
15 | }
| - `y` dropped here while still borrowed
16 | println!("{} {}", x, r);
|
实际上,上面这段代码错误的原因是S<'a>
中的两个字段的生命周期都是'a
,这导致let s = S { x: &x, y: &y };
和r = s.x
两个表达式存在歧义,前者要求x的生命周期和y一致,这个可以通过协变达成。但是后者要求s.x
的生命周期要大于y。这就尴尬了,你是没办法找出这样的一个生命周期大于y并且等于y。所以上面报错了。
只需要将S
的两个字段用不同的生命周期标注即可。这样就可以满足上面代码对于生命周期的要求。
struct S<'a, 'b> {
x: &'a i32,
y: &'b i32
}
use std::fmt::Display;
fn dynamic_thread_print(t: Box<dyn Display + Send>) {
std::thread::spawn(move || {
println!("{}", t);
}).join();
}
fn static_thread_print<T: Display + Send>(t: T) {
std::thread::spawn(move || {
println!("{}", t);
}).join();
}
error[E0310]: the parameter type `T` may not live long enough
--> src/main.rs:10:5
|
9 | fn static_thread_print<T: Display + Send>(t: T) {
| -- help: consider adding an explicit lifetime bound...: `T: 'static +`
10 | std::thread::spawn(move || {
| ^^^^^^^^^^^^^^^^^^ ...so that the type `[closure@src/main.rs:10:24: 12:6]` will meet its required lifetime bounds
这是因为std::thread::spawn
要求其内部捕获的类型需要满足'static
约束,因此会编译出错,要求给T添加'static
约束,但是为什么dynamic_thread_print
函数中没有要求t有'static
的生命周期约束呢?这是因为编译器给我们默认添加了。对于所有的trait
对象编译器有着一套规则来给其添加生命周期约束,下面是具体的规则。
use std::cell::Ref;
trait Trait {}
// 展开前
type T1 = Box<dyn Trait>;
// 展开后,Box<T> 没有对 T 的生命周期约束,所以推导为 'static
type T2 = Box<dyn Trait + 'static>;
// 展开前
impl dyn Trait {}
// 展开后
impl dyn Trait + 'static {}
// 展开前
type T3<'a> = &'a dyn Trait;
// 展开后,&'a T 要求 T: 'a, 所以推导为 'a
type T4<'a> = &'a (dyn Trait + 'a);
// 展开前
type T5<'a> = Ref<'a, dyn Trait>;
// 展开后,Ref<'a, T> 要求 T: 'a, 所以推导为 'a
type T6<'a> = Ref<'a, dyn Trait + 'a>;
trait GenericTrait<'a>: 'a {}
// 展开前
type T7<'a> = Box<dyn GenericTrait<'a>>;
// 展开后
type T8<'a> = Box<dyn GenericTrait<'a> + 'a>;
// 展开前
impl<'a> dyn GenericTrait<'a> {}
// 展开后
impl<'a> dyn GenericTrait<'a> + 'a {}
给予T ‘static这样的约束即可。