Rust生命周期
目录
Rust生命周期详解
一些规则
- &T 类型实现自动实现了Copy trait,所以可以直接拷贝
- &mut T 类型没有实现了Copy trait
- T 类型可以表示:&T 和 &mut T 和 T 类型
- 形变规则:
| Type | 在 ‘a 上的型变 | 在 T 上的型变 |
|---|---|---|
&'a T |
协变的 | 协变的 |
&'a mut T |
协变的 | 不变的 |
*const T |
协变的 | |
*mut T |
不变的 | |
[T] 和 [T; n] |
协变的 | |
fn() -> T |
协变的 | |
fn(T) -> () |
逆变的 | |
fn(T) -> T |
不变的 | |
std::cell::UnsafeCell<T> |
不变的 | |
std::marker::PhantomData<T> |
协变的 | |
dyn Trait<T> + 'a |
协变的 | 不变的 |
例子
|
|
生命周期省略规则
函数上的生命周期省略规则
- 参数中省略的每个生命周期类型参数都会(被推断)成为一个独立的生命周期类型参数。
- 如果参数中只使用了一个生命周期(省略或不省略都行),则将该生命周期作为所有省略的输出生命周期类型参数。
- 如果接受者(receiver)类型为 &Self 或 &mut Self,那么对 Self 的引用的生命周期会被作为所有省略的输出生命周期类型参数。
默认的 trait对象的生命周期
如果将 trait对象用作泛型类型的类型参数,则首先使用此容器泛型来尝试为此 trait对象推断一个约束(来替代那个假定的生命周期)。
- 如果存在来自此容器泛型的唯一约束,则该约束就为此 trait对象的默认约束
- 如果此容器泛型有多个约束,则必须指定一个约显式束为此 trait对象的默认约束
如果这两个规则都不适用,则使用该 trait对象的声明时的 trait约束:
- 如果原 trait 声明为单生命周期约束,则此 trait对象使用该约束作为默认约束。
- 如果 ‘static 被用做原 trait声明的任一一个生命周期约束,则此 trait对象使用 ‘static 作为默认约束。
- 如果原 trait声明没有生命周期约束,那么此 trait对象的生命周期会在表达式中根据上下文被推断出来,在表达式之外直接用 ‘static。
例子
|
|
分析:
- f1:
*rb的生命周期是'c S,又因为返回的是&'a S,又因为‘c S实现了Copy trait,可以直接拷贝,所以没问题。 - f2:
*rb的生命周期是'c S,又因为返回的是&'a S,又因为‘c S实现了Copy trait,可以直接拷贝,所以没问题。 - f3:
*rb的生命周期是'c mut S,又因为返回的是&'a S,又因为‘c mut S没有实现Copy trait,不能直接拷贝,所以存在问题。- 解决方案:添加生命周期约束:<‘a, ‘b:‘a>, 从
&'b &'a mut S可以看出,'b必须是'a的子生命周期,即:'a: 'b, 添加'b:'a后天可以判断出'a='b, 又因为*rb的生命周期是'c mut S,隐含了'c: 'b, 所以&'a S是'c mut S的子生命周期,所以可以解决问题。
- 解决方案:添加生命周期约束:<‘a, ‘b:‘a>, 从
- f4:
*rb的生命周期是'c S,又因为返回的是&'a S,又因为‘c S没有实现Copy trait,不能直接拷贝,所以存在问题,解决方案同f3。 - f5:
*rb的生命周期是'c S,又因为返回的是&'a mut S,又因为‘c S没有实现Copy trait,所以不能直接拷贝,所以存在问题,解决方案同f3。
|
|
分析:
-
fetch: 编译失败。对于动态分发会遵循:如果原 trait声明没有生命周期约束,那么此 trait对象的生命周期会在表达式中根据上下文被推断出来,在表达式之外直接用 ‘static。即它的生命周期为
Box<dyn Future<Output = ()> + 'static>,即可添加生命周期约束<'a, 'b: 'a>解决 -
fetchv2: 编译成功。对于静态分发,编译器会根据上下文推断出生命周期,所以不需要添加生命周期约束。