ゼロコスト抽象化
型状態はゼロコスト抽象化の優れた例でもあります。特定の動作を、コンパイル時の実行もしくは解析に移動する機能です。 これらの型状態は、実際のデータを含んでおらず、代わりにマーカとして使われています。 型状態はデータを含んでいないため、実行時、メモリ内に実際のデータはありません。
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は、存在しません。この関数を呼び出すと、通常、1つのアセンブリ命令にまとめられます。
そのアセンブリ命令は、定数のレジスタ値を、レジスタの位置へ格納します。
これは、開発した型状態インタフェースが、ゼロコスト抽象化であることを意味します。
GpioConfig
の状態を追跡するために、余分なCPU、RAM、コード領域を使用せず、直接レジスタアクセスするのと同じ機械語を表します。
ネスト
通常、これらの抽象化は、望み通りの深さでネストされます。使用される全てのコンポーネントが、ゼロサイズの型である限り、実行時には、構造体全体が存在しません。
複雑な構造体や深くネストした構造体については、全ての取り得る状態の組み合わせを定義することは、面倒です。 このような場合、全ての実装を生成するために、マクロが利用できます。