名称: m04-零成本抽象 描述: “关键:用于泛型、特征、零成本抽象。触发:E0277、E0308、E0599、泛型、特征、实现、dyn、where、单态化、静态分发、动态分发、impl Trait、特征约束不满足、泛型、特征、零成本抽象、单态化” 用户可调用: false
零成本抽象
层级 1:语言机制
核心问题
我们需要编译时还是运行时的多态?
在选择泛型或特征对象之前:
- 类型在编译时是否已知?
- 是否需要异构集合?
- 性能优先级是什么?
错误 → 设计问题
| 错误码 | 不要只说 | 而是问 |
|---|---|---|
| E0277 | “添加特征约束” | 这个抽象的层级是否正确? |
| E0308 | “修复类型” | 类型应该统一还是保持不同? |
| E0599 | “导入特征” | 这个特征是否是合适的抽象? |
| E0038 | “使其对象安全” | 我们真的需要动态分发吗? |
思考提示
在添加特征约束之前:
-
需要什么抽象?
- 相同行为,不同类型 → 特征
- 不同行为,相同类型 → 枚举
- 不需要抽象 → 具体类型
-
类型何时已知?
- 编译时 → 泛型(静态分发)
- 运行时 → 特征对象(动态分发)
-
权衡的优先级是什么?
- 性能 → 泛型
- 编译时间 → 特征对象
- 灵活性 → 视情况而定
向上追溯 ↑
当类型系统出现问题时:
E0277 (特征约束不满足)
↑ 问:抽象层级是否正确?
↑ 检查:m09-领域(正在抽象什么行为?)
↑ 检查:m05-类型驱动(应该使用新类型吗?)
| 持续错误 | 追溯至 | 问题 |
|---|---|---|
| 复杂的特征约束 | m09-领域 | 抽象是否正确? |
| 对象安全问题 | m05-类型驱动 | 类型状态能帮忙吗? |
| 类型爆炸 | m10-性能 | 能接受 dyn 的开销吗? |
向下推导 ↓
从设计到实现:
"需要对具有相同行为的类型进行抽象"
↓ 类型在编译时已知 → impl Trait 或泛型
↓ 类型在运行时确定 → dyn Trait
"需要不同类型的集合"
↓ 封闭集合 → 枚举
↓ 开放集合 → Vec<Box<dyn Trait>>
"需要返回不同类型"
↓ 相同类型 → impl Trait
↓ 不同类型 → Box<dyn Trait>
快速参考
| 模式 | 分发方式 | 代码大小 | 运行时成本 |
|---|---|---|---|
fn foo<T: Trait>() |
静态 | +膨胀 | 零 |
fn foo(x: &dyn Trait) |
动态 | 最小 | vtable 查找 |
impl Trait 返回 |
静态 | +膨胀 | 零 |
Box<dyn Trait> |
动态 | 最小 | 分配 + vtable |
语法比较
// 静态分发 - 类型在编译时已知
fn process(x: impl Display) { } // 参数位置
fn process<T: Display>(x: T) { } // 显式泛型
fn get() -> impl Display { } // 返回位置
// 动态分发 - 类型在运行时确定
fn process(x: &dyn Display) { } // 引用
fn process(x: Box<dyn Display>) { } // 拥有所有权
错误码参考
| 错误码 | 原因 | 快速修复 |
|---|---|---|
| E0277 | 类型未实现特征 | 添加实现或更改约束 |
| E0308 | 类型不匹配 | 检查泛型参数 |
| E0599 | 未找到方法 | 使用 use 导入特征 |
| E0038 | 特征非对象安全 | 使用泛型或重新设计 |
决策指南
| 场景 | 选择 | 原因 |
|---|---|---|
| 性能关键 | 泛型 | 零运行时成本 |
| 异构集合 | dyn Trait |
运行时类型不同 |
| 插件架构 | dyn Trait |
编译时类型未知 |
| 减少编译时间 | dyn Trait |
减少单态化 |
| 小型、已知类型集合 | enum |
无间接引用 |
对象安全性
一个特征是对象安全的,如果它:
- 没有
Self: Sized约束 - 不返回
Self - 没有泛型方法
- 对非对象安全的方法使用
where Self: Sized
反模式
| 反模式 | 为何不好 | 更好的做法 |
|---|---|---|
| 过度泛化一切 | 编译时间长,复杂度高 | 尽可能使用具体类型 |
对已知类型使用 dyn |
不必要的间接引用 | 泛型 |
| 复杂的特征层次结构 | 难以理解 | 更简单的设计 |
| 忽略对象安全性 | 限制灵活性 | 如有需要,为 dyn 做好规划 |
相关技能
| 何时 | 参见 |
|---|---|
| 类型驱动设计 | m05-类型驱动 |
| 领域抽象 | m09-领域 |
| 性能考虑 | m10-性能 |
| Send/Sync 约束 | m07-并发 |