4.5.3.2 高级准则
4 分钟阅读
译文 · 基于 Learning Rust
高级准则
原文链接: https://quinedot.github.io/rust-learning/dyn-elision-advanced.html
本节介绍如何为自己的泛型数据类型引导省略行为,并指出与上一节基本准则相比的一些例外。
引导自有类型的行为
声明带生命周期参数 'a 和 trait 参数 T: ?Sized 的自定义类型时,包含显式 T: 'a 约束会使省略行为与引用 &'a T 及 Ref<'a, T> 等 std 类型相同:
| |
若类型没有生命周期参数,或类型参数与生命周期参数之间没有约束,省略的 dyn Trait 生命周期默认为 'static,如 Box<T>。即使存在隐式 T: 'a 约束也如此。 例如:
| |
若在 struct 定义中显式写出 T: 'a,示例将可编译。
若 T: 'a 是类型的推断约束且 T: ?Sized,建议包含显式 T: 'a 约束。
尽管极其微妙,这确实是有意设计。
歧义约束
若类型定义中有多个生命周期约束,即使其中一个为 'static(或更一般地,即使一个生命周期已知长于另一个),约束仍被视为歧义。此类结构体罕见,若有,通常必须显式写出 dyn Trait 生命周期:
| |
但在函数体内,生命周期仍被推断;且推断独立于生命周期类型的任何注解:
| |
(这与参考手册文档相反,且讽刺地比非歧义类型更灵活。在此例中,生命周期将类似之前提到的生命周期交集推断。)
与类型别名的交互
使用类型别名时,type 别名上生命周期参数与类型参数之间的约束决定 dyn Trait 生命周期省略如何行为,覆盖被别名类型的约束(无论更强或更弱)。
| |
| |
见 issue 100270。 未记录。
关联类型和 GAT
dyn Trait 生命周期省略在此上下文适用。但需注意:
- 关联类型和 GAT 上的约束似乎无效
- 不允许省略非
dyn Trait生命周期
例如:
| |
| |
函数体内推断的例外
函数体内省略的 dyn Trait 生命周期被推断,也有例外。若有类似引用的类型,且用命名生命周期注解非 dyn Trait 的生命周期,则省略的 dyn Trait 生命周期与注解的生命周期相同(类似函数体外行为):
| |
根据参考手册,&dyn Trait 应总是如此行为。但若外层生命周期被省略或对 '_ 使用外层生命周期,dyn Trait 生命周期独立于引用生命周期推断:
| |
任何地方都没有记录,且与参考手册冲突。在此实现, 无团队输入或 FCP。🤷
但由于此行为,在函数体内注解生命周期很少见,因此遇到问题的概率较低。
尚未涵盖的内容
据我们所知,这涵盖了trait 本身没有生命周期约束时 dyn Trait 生命周期省略的行为。trait 本身的非 'static 生命周期约束导致更细微的行为;我们在下一节涵盖部分。
高级准则摘要
总之,忽略 trait 上的生命周期约束时,dyn Trait 生命周期省略有三类常见情况:
- 对没有(显式)生命周期约束的类型参数为
'static- 例如
Box<dyn Trait>(Box<dyn Trait + 'static>) - 例如
struct Unbounded<'a, T: ?Sized>(&'a T)
- 例如
- 对具有单一(显式)生命周期约束的类型参数为另一生命周期参数
- 例如
&'a dyn Trait(&'a dyn Trait + 'a) - 例如
Ref<'a, dyn Trait>(Ref<'a, dyn Trait + 'a>) - 例如
struct Bounded<'a, T: 'a + ?Sized>(&'a T)
- 例如
- 因多个约束而歧义(罕见)
- 例如
struct Weird<'a, T: 'a + 'static>(&'a T);
- 例如
各上下文中的行为:
static | impl | [G]AT | fn in | fn out | fn body | |
|---|---|---|---|---|---|---|
Box<dyn Trait> | 'static | 'static | 'static | 'static | 'static | Inferred |
&dyn Trait | Ref | Ref | E0637 | Ref | Ref | Inferred |
&'a dyn Trait | Ref | Ref | Ref | Ref | Ref | Ref |
| Ambig. | E0228 | E0228 | E0228 | E0228 | E0228 | Inferred |
附注:
type别名约束优先于被别名类型约束- 关联类型和 GAT 约束不影响默认
对比,「普通」省略规则如下:
static | impl | [G]AT | fn in | fn out | fn body | |
|---|---|---|---|---|---|---|
Box<dyn Tr + '_> | 'static | Fresh | E0637 | Fresh | Elision | Inferred |
&(dyn Trait + '_) | 'static | Fresh | E0637 | Fresh | Elision | Inferred |
&'a (dyn Trait + '_) | 'static | Fresh | E0637 | Fresh | Elision | Inferred |
Ambig. with '_ | 'static | Fresh | E0637 | Fresh | Elision | Inferred |