Das Entdecken von Rust Closures und ihrem Capturing-Verhalten

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 untersuchen wir Closures in Rust und ihr Capturing-Verhalten, das es ihnen ermöglicht, Variablen per Referenz, mutabler Referenz oder Wert zu erfassen, je nachdem, welche Anforderungen das Closure hat.

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.


Skills Graph

%%%%{init: {'theme':'neutral'}}%%%% flowchart RL rust(("Rust")) -.-> rust/MemorySafetyandManagementGroup(["Memory Safety and Management"]) rust(("Rust")) -.-> rust/DataStructuresandEnumsGroup(["Data Structures and Enums"]) rust(("Rust")) -.-> rust/ErrorHandlingandDebuggingGroup(["Error Handling and Debugging"]) rust(("Rust")) -.-> rust/AdvancedTopicsGroup(["Advanced Topics"]) rust(("Rust")) -.-> rust/BasicConceptsGroup(["Basic Concepts"]) rust(("Rust")) -.-> rust/FunctionsandClosuresGroup(["Functions and Closures"]) rust/BasicConceptsGroup -.-> rust/variable_declarations("Variable Declarations") rust/BasicConceptsGroup -.-> rust/mutable_variables("Mutable Variables") rust/FunctionsandClosuresGroup -.-> rust/function_syntax("Function Syntax") rust/FunctionsandClosuresGroup -.-> rust/expressions_statements("Expressions and Statements") rust/MemorySafetyandManagementGroup -.-> rust/lifetime_specifiers("Lifetime Specifiers") rust/DataStructuresandEnumsGroup -.-> rust/method_syntax("Method Syntax") rust/ErrorHandlingandDebuggingGroup -.-> rust/error_propagation("Error Propagation") rust/AdvancedTopicsGroup -.-> rust/operator_overloading("Traits for Operator Overloading") subgraph Lab Skills rust/variable_declarations -.-> lab-99323{{"Das Entdecken von Rust Closures und ihrem Capturing-Verhalten"}} rust/mutable_variables -.-> lab-99323{{"Das Entdecken von Rust Closures und ihrem Capturing-Verhalten"}} rust/function_syntax -.-> lab-99323{{"Das Entdecken von Rust Closures und ihrem Capturing-Verhalten"}} rust/expressions_statements -.-> lab-99323{{"Das Entdecken von Rust Closures und ihrem Capturing-Verhalten"}} rust/lifetime_specifiers -.-> lab-99323{{"Das Entdecken von Rust Closures und ihrem Capturing-Verhalten"}} rust/method_syntax -.-> lab-99323{{"Das Entdecken von Rust Closures und ihrem Capturing-Verhalten"}} rust/error_propagation -.-> lab-99323{{"Das Entdecken von Rust Closures und ihrem Capturing-Verhalten"}} rust/operator_overloading -.-> lab-99323{{"Das Entdecken von Rust Closures und ihrem Capturing-Verhalten"}} end

Capturing

Closures sind von Natur aus flexibel und werden das tun, was die Funktionalität erfordert, um das Closure ohne Annotation zu machen. Dies ermöglicht es, das Capturing flexibel an den Anwendungsfall anzupassen, manchmal verschiebend und manchmal entleihend. Closures können Variablen erfassen:

  • per Referenz: &T
  • per mutabler Referenz: &mut T
  • per Wert: T

Sie bevorzugen es, Variablen per Referenz zu erfassen und gehen nur niedriger, wenn erforderlich.

fn main() {
    use std::mem;

    let color = String::from("green");

    // Ein Closure, um `color` auszugeben, das sofort `color` entleiht (`&`) und
    // die Entleihe und das Closure in der `print`-Variable speichert. Es wird
    // bis zum letzten Mal die Entleihe beibehalten, wenn `print` verwendet wird.
    //
    // `println!` erfordert nur Argumente per unveränderlicher Referenz, daher
    // erlegt es keine restriktiveren Anforderungen.
    let print = || println!("`color`: {}", color);

    // Rufen Sie das Closure mit der Entleihe auf.
    print();

    // `color` kann erneut unverändert entliehen werden, da das Closure nur
    // eine unveränderliche Referenz auf `color` hält.
    let _reborrow = &color;
    print();

    // Ein Verschieben oder erneute Entleihe ist nach der letzten Verwendung von
    // `print` möglich
    let _color_moved = color;


    let mut count = 0;
    // Ein Closure, um `count` zu erhöhen, könnte entweder `&mut count` oder
    // `count` nehmen, aber `&mut count` ist weniger restriktiv, daher nimmt
    // es das. Entleiht sofort `count`.
    //
    // Ein `mut` ist erforderlich bei `inc`, da eine `&mut` innerhalb gespeichert
    // ist. Daher mutiert das Aufrufen des Closures das Closure, was einen `mut`
    // erfordert.
    let mut inc = || {
        count += 1;
        println!("`count`: {}", count);
    };

    // Rufen Sie das Closure mit einer mutablen Entleihe auf.
    inc();

    // Das Closure entleiht immer noch `count` mutabel, da es später aufgerufen
    // wird. Ein Versuch, es erneut zu entleihen, führt zu einem Fehler.
    // let _reborrow = &count;
    // ^ TODO: Versuchen Sie, diese Zeile auszukommentieren.
    inc();

    // Das Closure muss `&mut count` nicht mehr entleihen. Daher ist es
    // möglich, es erneut zu entleihen, ohne einen Fehler zu erhalten
    let _count_reborrowed = &mut count;


    // Ein nicht kopierbarer Typ.
    let movable = Box::new(3);

    // `mem::drop` erfordert `T`, daher muss dies per Wert genommen werden. Ein
    // kopierbarer Typ würde in das Closure kopiert, wobei der Originalwert
    // unberührt bleibt.
    // Ein nicht kopierbarer Typ muss verschoben werden, daher wird `movable`
    // sofort in das Closure verschoben.
    let consume = || {
        println!("`movable`: {:?}", movable);
        mem::drop(movable);
    };

    // `consume` konsumiert die Variable, daher kann dies nur einmal aufgerufen
    // werden.
    consume();
    // consume();
    // ^ TODO: Versuchen Sie, diese Zeile auszukommentieren.
}

Das Verwenden von move vor den vertikalen Schläuchen zwingt das Closure, die Besitznahme der erfassten Variablen zu übernehmen:

fn main() {
    // `Vec` hat nicht-kopierende Semantik.
    let haystack = vec![1, 2, 3];

    let contains = move |needle| haystack.contains(needle);

    println!("{}", contains(&1));
    println!("{}", contains(&4));

    // println!("There're {} elements in vec", haystack.len());
    // ^ Wenn Sie die obige Zeile auskommentieren, wird ein
    // Kompilierfehler auftreten, da der Entleihprüfer nicht erlaubt,
    // die Variable erneut zu verwenden, nachdem sie verschoben wurde.

    // Wenn Sie `move` aus der Signatur des Closures entfernen, wird das
    // Closure die _haystack_-Variable unverändert entleihen, daher ist
    // _haystack_ immer noch verfügbar und das Auskommentieren der
    // obigen Zeile verursacht keinen Fehler.
}

Zusammenfassung

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