第 8 章 多态与架构选型——静态分发、动态分发与 OOP
在前七章中,我们建立了一整套编译期静态确定的模型:变量的大小在编译期算死、释放时机在作用域末尾静态插入、泛型 <T: Trait> 在编译期通过单态化生成多份专属机器码(静态分发)。
但当程序进入更复杂的动态业务场景——例如函数的返回值类型取决于运行时的用户输入,或者一个 Vec 数组需要同时装入十几种实现了同一个 Trait 的不同结构体时——编译期单态化就会立刻撞上它的物理边界。
本章将带你跨过这道从「编译期静态」通往「运行时动态」的分水岭,按四步推进:
- 静态与动态的全局大局观(
impl Trait与单态化的两道边界):掌握impl Trait在参数与返回值位置的语法,亲历静态单态化在「运行时分支返回不同类型」与「异构集合」面前的报错,从而拉通全书「编译期静态结算 vs 运行时动态结算」的全局切换开关。 - 动态分发与
dyn Trait虚表胖指针:迎来与第 4 章切片&[T]的第二次胖指针会师——看清为什么擦除具体类型后的&dyn Trait在栈上占 16 字节(data_ptr + vtable_ptr),以及 CPU 如何在运行时通过虚表(vtable)查表调用方法。 - 静态分发 vs 动态分发正面交锋与
dyn兼容性:全方位对比<T: Trait>与&dyn Trait的内存布局、代码体积、内联优化与调用成本,并从虚表物理结构直接推导出为什么有的 Trait 不能写成dyn Trait(dyn兼容性)。 - 没有
class和extends,如何组织代码与选型多态?:拆解传统面向对象class的三合一包袱,用组合与 Trait 替代继承,并立下工程与代码审查(Code Review)中的终极多态选型铁律——闭合集合用enum(ADT),开放集合用泛型或dyn Trait。
读完本章,检验自己的四个问题
Section titled “读完本章,检验自己的四个问题”- 为什么
fn make(flag: bool) -> impl Summary在if和else分支返回两个都实现了Summary的不同结构体时会编译失败?这暴露了编译期静态单态化的什么物理限制? - 为什么
&Article在 64 位平台上占 8 字节,而转成&dyn Summary后立刻变成了 16 字节?多出来的那 8 个字节指向哪里、里面存着什么? - 为什么一个包含
fn clone_self(&self) -> Self或泛型方法fn process<U>(&self, x: U)的 Trait,编译器禁止将它写成&dyn Trait? - 在设计系统架构或审查 AI 生成的代码时,面对「多种业务形态共享行为」的需求,你依据什么标准在
enum、泛型<T: Trait>与Box<dyn Trait>之间做取舍?