区别
特性 | 泛型(静态分发) | 特征对象(动态分发) |
决策时机 | 编译时单态化(生成具体类型的代码) | 运行时通过vtable查找方法 |
运行性能 | 零运行时开销(直接内联调用) | 有额外开销(指针跳转+vtable) |
二进制大小 | 可能增大(为每个类型生成代码) | 较小(共享一份trait代码) |
灵活性 | 类型必须在编译时确定 | 可在运行时动态改变具体类型 |
创建特征对象对特性的要求:
方法不能返回Self、&Self(编译时无法确定具体类型)
方法不能使用泛型参数(无法为未知类型提前实例化)
方法不能是静态的(即必须有 &self
、&mut self
等接收者)
适用场景
异构集合:在容器中存储不同类型(如 GUI 组件列表)。
延迟绑定:运行时决定具体类型(如插件系统)。
减少编译产物大小:避免泛型单态化膨胀。
与遗留代码交互:模拟 OO 风格接口。
限制与权衡
性能开销:方法调用需两次指针跳转(数据 + vtable)。
无法内联:编译器无法优化动态调用。
类型擦除:特征对象丢失具体类型信息(需通过
downcast
恢复,但需额外机制如Any
)
总结
特征对象是 Rust 动态分发的核心工具,通过 dyn Trait + 指针
实现运行时多态。它牺牲少量性能换取灵活性,适用于需要处理未知类型或异构集合的场景。理解其底层机制(胖指针 + vtable)和对象安全规则是高效使用的关键。