Programmiersprache Rust 1.64 erweitert asynchrone Programmierung mit IntoFuture
Neben einem neuen Trait für die asynchrone Programmierung überführt das Release Typ-Aliase für das Zusammenspiel mit C in die Core-Library.
- Rainald Menge-Sonnentag
Im turnusmäßigen Sechswochentakt ist Rust 1.64 erschienen. Das Release implementiert das Trait IntoFuture
für die asynchrone Programmierung. Außerdem sind einige C-Typen nun von der Standard- in die Core-Library gewandert, um sie vor allem in der Embedded-Programmierung nutzen zu können.
Auf Ökosystemseite ist neuerdings der rust-analyzer
Bestandteil der Toolsammlung von Rust. Das Werkzeug ist eine Implementierung des Language Server Protocol, um Funktionen wie Autovervollständigung in IDEs und Sourcecode-Editoren wie Visual Studio Code, Emacs und Vim zu nutzen. Um den Language Server für Rust zu installieren, dient die Zeile rustup component add rust-analyzer
.
Wandlung in die Zukunft
Rust hat das Async-Await-Pattern mit Rust 1.39 Ende 2019 eingeführt. sie nutzt das Future
-Trait Einzug, das einen zukünftigen Wert beschreibt. Traits sind Rusts Umsetzung von Interfaces. Über eine poll
-Methode lässt sich der Wert abfragen. Die Methode wartet nicht, bis der Wert tatsächlich da ist, blockiert also nicht, aber kann dem Aufrufer mitteilen, dass die Future
noch nicht bereit ist. Mit dem Keyword await
lässt sich die Ausführung einer Funktion so lange aufhalten, bis die Future
fertig durchlaufen ist.
Das aktuelle Release führt mit IntoFuture
ein neues Trait ein, das einen beliebigen Typ in ein Future
wandelt. Die Umsetzung ist an das in Rust 1.53 auf Arrays erweiterte Trait IntoIterator
angelehnt, der das Iterieren über die Elemente eines Typs ermöglicht.
Das IntoFuture
-Trait benötigt die Typen für den zugehörigen Output (type Output
) und die Future
(type IntoFuture
) sowie eine Methode (fn into_future(self)
), die das Objekt vorbereitet und eine Future
erstellt. .await
ruft letztere Methode auf, bevor es die Ergebnisse abruft beziehungsweise abwartet.
Folgender Code aus der Rust-Dokumentation zeigt den Einsatz des Trait an dem einfachen, wenn auch konstruierten Beispiel eines Struct für die Multiplikation einer Zahl num
mit einem Faktor factor
:
use std::future::{ready, Ready, IntoFuture};
/// Eventually multiply two numbers
pub struct Multiply {
num: u16,
factor: u16,
}
impl Multiply {
/// Construct a new instance of `Multiply`.
pub fn new(num: u16, factor: u16) -> Self {
Self { num, factor }
}
/// Set the number to multiply by the factor.
pub fn number(mut self, num: u16) -> Self {
self.num = num;
self
}
/// Set the factor to multiply the number with.
pub fn factor(mut self, factor: u16) -> Self {
self.factor = factor;
self
}
}
impl IntoFuture for Multiply {
type Output = u16;
type IntoFuture = Ready<Self::Output>;
fn into_future(self) -> Self::IntoFuture {
ready(self.num * self.factor)
}
}
async fn run() {
let num = Multiply::new(0, 0) // initialize the builder to
// number: 0, factor: 0
.number(2) // change the number to 2
.factor(2) // change the factor to 2
.await; // convert to future and .await
assert_eq!(num, 4);
}
Die eigentliche Implementierung des neuen Trait findet sich in dem Block impl IntoFuture for Multiply
. Auf die neue Umsetzung zu setzen lohnt sich laut Dokumentation vor allem für asynchrone Builder-Typen, für die vor dem Await-Prozess mehrfache Änderungen der Werte anstehen. Im Blogbeitrag zu Rust 1.64 findet sich ein Beispiel zu einer Storage-Abfrage.
Der Vorschlag zur Implementierung eines IntoFuture
kam bereits Ende 2019 kurz nach der Umsetzung von Async/Await auf, führte allerdings wohl zunächst zu Performance-Problemen, weshalb er zunächst wieder aus der Sprache herausgenommen wurde.
Typen im Kern
Eine weitere Änderung betrifft vor allem die Embedded-Entwicklung: Einige Typ-Aliase wandern von der Standard in die Core-Library. Letztere ist die minimale Umsetzung, die auf Dependencies verzichtet und auch in Code aus Paketen (Crates) verfügbar ist, die mit #![no_std]
gekennzeichnet sind, also auf die Standardbibliothek verzichten.
Rust 1.64 bietet nun diverse Typ-Aliase für das Foreign-Function-Interface (FFI) zu C in core::ffi
. Dazu gehören die Aliase, mit c_
beginnen wie c_uint
und c_ulong
sowie die String-Umsetzung core::ffi::CStr
.
Weitere Details zu Rust 1.64 wie das Anstoßen eines Cargo-Build-Prozesses für mehrere Targets lassen sich dem Rust-Blog entnehmen. Wie üblich können Entwicklerinnen und Entwickler, die Rust bereits installiert haben, das aktuelle Release über rustup update stable
herunterladen. Für diejenigen, die noch kein Rust verwenden, ist das rustup
-Tool auf der Download-Seite separat verfügbar.
(rme)