结论:泛型 T: Trait 是静态分发——编译器为每个具体类型单态化一份代码,零运行时开销,但同一容器只能装一种类型且代码体积膨胀;Box<dyn Trait> 是动态分发——通过虚表(vtable)在运行时解析方法,允许多种类型混存,代价是一次间接调用和失去内联机会。

展开:选型看两点:1)集合内类型是否异构——插件列表、GUI 控件树这种"运行时才确定有哪些类型"的场景必须 dyn;2)性能敏感度——热路径、需要内联优化的计算密集代码用泛型。约束:trait 要能做 trait object 必须满足 object safety——方法不能有 Self 返回类型(构造器类方法除外需 where Self: Sized)、不能有泛型参数,因为虚表里无法表达。易错点:dyn Trait 本身是不定长类型(DST),必须放在指针后面:Box<dyn Trait>&dyn TraitArc<dyn Trait>

trait Draw { fn draw(&self); }
fn draw_all(items: &[Box<dyn Draw>]) {  // 动态分发:可混放 Button/Text
    for i in items { i.draw(); }
}
fn draw_one<T: Draw>(item: &T) { item.draw(); } // 静态分发

追问方向:vtable 布局(数据指针 + 元数据指针的胖指针)、enum 为何常是比 trait object 更简单的选择。