rust / expert
Snippet
Kompilierzeit-Erzwingung von API-Zuständen durch das Typestate-Muster
Dieses Snippet implementiert das Typestate-Muster, welches das Typsystem von Rust nutzt, um gültige Zustandsübergänge eines Objekts zur Kompilierzeit zu erzwingen. Durch den Verbrauch von `self` in Übergangsmethoden (wie `connect`) garantieren wir, dass veraltete Zustände nicht wiederverwendet werden können, was logische Fehler zur Laufzeit ausschließt.
snippet.rs
rust
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
pub struct Uninitialized;pub struct Connected {pub socket_id: u32,}pub struct Connection<State> {pub host: String,pub state: State,}impl Connection<Uninitialized> {pub fn new(host: &str) -> Self {Self {host: host.to_string(),state: Uninitialized,}}pub fn connect(self) -> Connection<Connected> {Connection {host: self.host,state: Connected { socket_id: 101 },}}}impl Connection<Connected> {pub fn send(&self, data: &[u8]) {println!("Sending to socket {}: {:?}", self.state.socket_id, data);}}
Erklärung
1
pub struct Connection<State>
Deklariert einen generischen Verbindungstyp, der durch seinen aktuellen Lebenszyklus-Zustand parametrisiert wird.
2
impl Connection<Uninitialized>
Implementiert Funktionen, die nur gültig sind, wenn die Verbindung im nicht initialisierten Zustand ist.
3
pub fn connect(self) -> Connection<Connected>
Konsumiert den Besitz von `self` (dem uninitialized Zustand) und gibt eine neue Verbindung im connected Zustand zurück.
4
impl Connection<Connected>
Implementiert Funktionen (wie `send`), die ausschließlich verfügbar sind, nachdem eine Verbindung erfolgreich hergestellt wurde.
5
self.state.socket_id
Greift auf Daten innerhalb der `Connected`-Zustandsstruktur zu, die nur in diesem Zustand existieren.