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.

In Pocket speichern vorlesen Druckansicht 3 Kommentare lesen
Lesezeit: 4 Min.
Von
  • 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.

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.

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)