零成本抽象

类型状态也是零成本抽象的一个极佳例子 - 将某些行为转移到编译时执行或分析的能力。这些类型状态不包含任何实际数据,而是用作标记。由于它们不包含任何数据,因此它们在运行时在内存中没有实际表示。

use core::mem::size_of;

let _ = size_of::<Enabled>();    // == 0
let _ = size_of::<Input>();      // == 0
let _ = size_of::<PulledHigh>(); // == 0
let _ = size_of::<GpioConfig<Enabled, Input, PulledHigh>>(); // == 0

零大小类型

struct Enabled;

像这样定义的结构被称为零大小类型,因为它们不包含任何实际数据。尽管这些类型在编译时表现得“真实” - 您可以复制它们、移动它们、获取它们的引用等等,但优化器会完全将其剥离。

在这段代码片段中

pub fn into_input_high_z(self) -> GpioConfig<Enabled, Input, HighZ> {
    self.periph.modify(|_r, w| w.input_mode().high_z());
    GpioConfig {
        periph: self.periph,
        enabled: Enabled,
        direction: Input,
        mode: HighZ,
    }
}

我们返回的 `GpioConfig` 在运行时永远不存在。调用此函数通常会简化为一条汇编指令 - 将一个常数寄存器值存储到一个寄存器位置。这意味着我们开发的类型状态接口是零成本抽象 - 它不会使用更多的 CPU、RAM 或代码空间来跟踪 `GpioConfig` 的状态,并且渲染与直接寄存器访问相同的机器代码。

嵌套

一般来说,这些抽象可以根据需要进行深度嵌套。只要所有使用的组件都是零大小类型,整个结构在运行时就不会存在。

对于复杂或深度嵌套的结构,定义所有可能的状态组合可能会很繁琐。在这些情况下,可以使用宏来生成所有实现。