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.
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.
Erweiterbare Structs, Enums und Enum-Varianten
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.
Verbesserungen bei Makros und Attributen
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:
- Rust als sichere Programmiersprache für systemnahe und parallele Software
- Task- und Datenparallelität mit Rust
- Jan-Erik Rediger: Entwickler aus allen Programmiersprachen kommen zu Rust
(map)