Als Eingabeparameter

RustRustBeginner
Jetzt üben

This tutorial is from open-source community. Access the source code

💡 Dieser Artikel wurde von AI-Assistenten übersetzt. Um die englische Version anzuzeigen, können Sie hier klicken

Einführung

In diesem Lab lernen wir, dass wenn wir in Rust Funktionen schreiben, die eine Closure als Eingabeparameter akzeptieren, der vollständige Typ der Closure mithilfe eines der Traits: Fn, FnMut oder FnOnce annotiert werden muss. Diese Traits bestimmen, wie die Closure den eingefangenen Wert verwendet, entweder per Referenz, mutabler Referenz oder Wert. Der Compiler fängt Variablen in der am wenigsten restriktiven Weise möglich basierend auf dem gewählten Trait für die Closure ein.

Hinweis: Wenn das Lab keinen Dateinamen angibt, können Sie einen beliebigen Dateinamen verwenden. Beispielsweise können Sie main.rs verwenden und es mit rustc main.rs &&./main kompilieren und ausführen.

Als Eingabeparameter

Während Rust in der Regel die Art der Variablenfassung ohne Typangabe auf dem Laufenden bestimmt, ist diese Mehrdeutigkeit bei der Schreibung von Funktionen nicht erlaubt. Wenn eine Closure als Eingabeparameter verwendet wird, muss der vollständige Typ der Closure mithilfe eines der folgenden Traits annotiert werden. Diese werden durch die Art der Verwendung des eingefangenen Werts in der Closure bestimmt. In abnehmender Reihenfolge der Einschränkung sind dies:

  • Fn: Die Closure verwendet den eingefangenen Wert per Referenz (&T)
  • FnMut: Die Closure verwendet den eingefangenen Wert per mutabler Referenz (&mut T)
  • FnOnce: Die Closure verwendet den eingefangenen Wert per Wert (T)

Variablenweise wird der Compiler die Variablen in der am wenigsten restriktiven Weise fassen.

Betrachten Sie beispielsweise einen Parameter, der als FnOnce annotiert ist. Dies besagt, dass die Closure den Wert möglicherweise per &T, &mut T oder T fangen kann, aber der Compiler wählt letztendlich basierend auf der Verwendung der eingefangenen Variablen in der Closure.

Dies liegt daran, dass wenn eine Verschiebung möglich ist, auch jede Art von Verweis möglich sein sollte. Beachten Sie, dass die Umkehrung nicht zutrifft. Wenn der Parameter als Fn annotiert ist, ist es nicht möglich, Variablen per &mut T oder T zu fangen. Allerdings ist &T möglich.

Im folgenden Beispiel können Sie versuchen, die Verwendung von Fn, FnMut und FnOnce zu tauschen, um zu sehen, was passiert:

// Eine Funktion, die eine Closure als Argument nimmt und aufruft.
// <F> bedeutet, dass F ein "Generischer Typparameter" ist
fn apply<F>(f: F) where
    // Die Closure nimmt keine Eingabe und gibt nichts zurück.
    F: FnOnce() {
    // ^ TODO: Versuchen Sie, dies in `Fn` oder `FnMut` zu ändern.

    f();
}

// Eine Funktion, die eine Closure nimmt und einen `i32` zurückgibt.
fn apply_to_3<F>(f: F) -> i32 where
    // Die Closure nimmt einen `i32` und gibt einen `i32` zurück.
    F: Fn(i32) -> i32 {

    f(3)
}

fn main() {
    use std::mem;

    let greeting = "hello";
    // Ein nicht kopierbarer Typ.
    // `to_owned` erstellt von einem referenzierten Datum ein eigenes
    let mut farewell = "goodbye".to_owned();

    // Fang 2 Variablen ein: `greeting` per Referenz und
    // `farewell` per Wert.
    let diary = || {
        // `greeting` ist per Referenz: erfordert `Fn`.
        println!("Ich sagte {}.", greeting);

        // Die Mutation zwingt `farewell`, per mutabler
        // Referenz eingefangen zu werden. Jetzt erfordert es `FnMut`.
        farewell.push_str("!!!");
        println!("Dann schrie ich {}.", farewell);
        println!("Jetzt kann ich schlafen. zzzzz");

        // Manuelles Aufrufen von drop zwingt `farewell`,
        // per Wert eingefangen zu werden. Jetzt erfordert es `FnOnce`.
        mem::drop(farewell);
    };

    // Rufe die Funktion auf, die die Closure anwendet.
    apply(diary);

    // `double` erfüllt die Trait-Bedingung von `apply_to_3`
    let double = |x| 2 * x;

    println!("3 verdoppelt: {}", apply_to_3(double));
}

Zusammenfassung

Herzlichen Glückwunsch! Sie haben das Lab As Input Parameters abgeschlossen. Sie können in LabEx weitere Labs ausprobieren, um Ihre Fähigkeiten zu verbessern.