Bewusst unvollständig: Programmiersprache Rust 1.40 führt #[non_exhaustive] ein

Mit dem neuen Attribut können Entwickler Structs, Enums und Enum-Varianten kennzeichnen, die sie später noch erweitern wollen.

In Pocket speichern vorlesen Druckansicht 25 Kommentare lesen
Das Warten hat ein Ende: Rust 1.39 erhält planmäßig async/await-Feature
Lesezeit: 3 Min.

Mit dem Stable Release Rust 1.40 legt Mozilla zum Jahresende noch ein umfassendes Update der Programmiersprache vor. Neben Verbesserungen bei macros!() and #[attribute] sind nun endlich auch die Warnungen zu Borrow-check Migration echte Fehler in Rust 2015. Die wohl wichtigste Neuerung im Release 1.40 ist aber die Einführung von "Unvollständigkeit" als Teil der Bemühungen um mehr Stabilität in Rust. Entwickler können nun Structs, Enums und Enum-Varianten, denen sie zu einem späteren Zeitpunkt möglicherweise noch Felder hinzufügen möchten, mit #[non_exhaustive] kennzeichnen.

Der Einsatz von #[non_exhaustive] empfiehlt sich beispielsweise für Library-Entwickler, die Crates mit öffentlichen Structs mit einer noch nicht endgültigen Zahl von Feldern entwerfen. Binden Anwender diese nämlich mit festen Bezügen zu den vorhandenen Feldern in ihren Code ein, so kann es bei späteren Releases mit neu hinzugefügten Feldern zu Brüchen kommen. Dem können Entwickler zwar vorbeugen, in dem sie die Felder als privat markieren, müssen dann aber auch die damit verbundenen Einschränkungen hinnehmen. Mit dem Attribut #[non_exhaustive] steht nun eine Alternative zur Verfügung. Angehängt an ein Struct oder eine Variante eines Enum, hindert das Attribut Code außerhalb des definierenden Crates daran, die Structs/Enums zu erstellen.

Das Attribut setzt dazu die öffentliche Sichtbarkeit auf pub(crate) herab, wie das folgende Codebeispiel anhand eines Crate alpha und des davon abhängigen Crate beta verdeutlicht:

// alpha/lib.rs:

#[non_exhaustive]
struct Foo {
pub a: bool,
}

enum Bar {
#[non_exhaustive]
Variant { b: u8 }
}

fn make_foo() -> Foo { ... }
fn make_bar() -> Bar { ... }

// beta/lib.rs:

let x = Foo { a: true }; //~ ERROR
let Foo { a } = make_foo(); //~ ERROR

// `beta` will still compile when more fields are added.
let Foo { a, .. } = make_foo(); //~ OK


let x = Bar::Variant { b: 42 }; //~ ERROR
let Bar::Variant { b } = make_bar(); //~ ERROR
let Bar::Variant { b, .. } = make_bar(); //~ OK
// -- `beta` will still compile...

Kommt #[non_exhaustive] in Verbindung mit Enums zum Einsatz, stellt das Attribut sicher, dass weitere Varianten zu späteren Zeitpunkten hinzugefügt werden können, in dem es andere Crates vom umfassenden Pattern-Matching in der Funktion Ordering abhält.

Funktionsähnliche und attributprozedurale Makros können nun macro_rules! ausgeben, sodass Entwickler Makros nutzen können, um neue Makros zu generieren. Außerdem hat das Rust-Team den in macro_rules! eingesetzten Pattern-Matcher meta aktualisiert, damit er die neuere Attribute-Syntax korrekt verarbeitet. Darüber hinaus lassen sich funktionsähnliche und prozedurale Makros nun auch in externen Blöcken und Type-Positionen einsetzen.

Eine komplette Übersicht aller Neuerungen in Rust 1.40 findet sich im Blogbeitrag zum Release.

Siehe dazu auf heise Developer:

(map)