Abstraktionen ohne Kosten
Typzustände (Type States) sind zudem ein hervorragendes Beispiel für „Zero-Cost Abstractions“ – also die Möglichkeit, bestimmte Verhaltensweisen in die Kompilierzeit zu verlagern (sei es zur Ausführung oder zur Analyse). Diese Typzustände enthalten keine eigentlichen Daten, sondern dienen als Markierungen. Da sie keine Daten enthalten, besitzen sie zur Laufzeit keine tatsächliche Repräsentation im Speicher:
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>>(); // == 0Typen der Größe Null
struct Enabled;Strukturen dieser Art werden als Null-Typen bezeichnet, da sie keine tatsächlichen Daten enthalten. Obwohl sich diese Typen zur Kompilierzeit „real“ verhalten – man kann sie kopieren, verschieben, Referenzen darauf erstellen usw. –, werden sie vom Optimierer vollständig entfernt.
In diesem Code-Ausschnitt:
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,
}
}Das von uns zurückgegebene GpioConfig-Objekt existiert zur Laufzeit nicht. Der Aufruf dieser Funktion läuft im Wesentlichen auf einen einzigen Assembler-Befehl hinaus: das Speichern eines konstanten Registerwerts an einer bestimmten Registeradresse. Das bedeutet, dass die von uns entwickelte „Type-State“-Schnittstelle eine Abstraktion ohne Laufzeitkosten (Zero-Cost-Abstraction) darstellt – sie verbraucht weder zusätzliche CPU- oder RAM-Ressourcen noch zusätzlichen Programmspeicher für die Zustandsverwaltung von GpioConfig und führt zu demselben Maschinencode wie ein direkter Registerzugriff.
Verschachtelung
Im Allgemeinen lassen sich diese Abstraktionen beliebig tief verschachteln. Solange es sich bei allen verwendeten Komponenten um Typen ohne Größe (Zero-Sized Types) handelt, existiert die gesamte Struktur zur Laufzeit nicht.
Bei komplexen oder tief verschachtelten Strukturen kann es mühsam sein, alle möglichen Zustandskombinationen zu definieren. In solchen Fällen lassen sich Makros verwenden, um sämtliche Implementierungen zu generieren.