Pfade in den Gültigkeitsbereich mit dem Schlüsselwort use bringen

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

Willkommen zu Bringing Paths Into Scope With the Use Keyword. Dieser Lab ist ein Teil des Rust Buchs. Du kannst deine Rust-Fähigkeiten in LabEx üben.

In diesem Lab lernen wir, wie wir Pfade in den Gültigkeitsbereich bringen, indem wir das use-Schlüsselwort verwenden, um Kurzschlüsse für das Aufrufen von Funktionen und Modulen zu erstellen.


Skills Graph

%%%%{init: {'theme':'neutral'}}%%%% flowchart RL rust(("Rust")) -.-> rust/BasicConceptsGroup(["Basic Concepts"]) rust(("Rust")) -.-> rust/DataTypesGroup(["Data Types"]) rust(("Rust")) -.-> rust/FunctionsandClosuresGroup(["Functions and Closures"]) rust(("Rust")) -.-> rust/DataStructuresandEnumsGroup(["Data Structures and Enums"]) rust/BasicConceptsGroup -.-> rust/variable_declarations("Variable Declarations") rust/BasicConceptsGroup -.-> rust/mutable_variables("Mutable Variables") rust/DataTypesGroup -.-> rust/type_casting("Type Conversion and Casting") rust/FunctionsandClosuresGroup -.-> rust/function_syntax("Function Syntax") rust/FunctionsandClosuresGroup -.-> rust/expressions_statements("Expressions and Statements") rust/DataStructuresandEnumsGroup -.-> rust/method_syntax("Method Syntax") subgraph Lab Skills rust/variable_declarations -.-> lab-100404{{"Pfade in den Gültigkeitsbereich mit dem Schlüsselwort use bringen"}} rust/mutable_variables -.-> lab-100404{{"Pfade in den Gültigkeitsbereich mit dem Schlüsselwort use bringen"}} rust/type_casting -.-> lab-100404{{"Pfade in den Gültigkeitsbereich mit dem Schlüsselwort use bringen"}} rust/function_syntax -.-> lab-100404{{"Pfade in den Gültigkeitsbereich mit dem Schlüsselwort use bringen"}} rust/expressions_statements -.-> lab-100404{{"Pfade in den Gültigkeitsbereich mit dem Schlüsselwort use bringen"}} rust/method_syntax -.-> lab-100404{{"Pfade in den Gültigkeitsbereich mit dem Schlüsselwort use bringen"}} end

Pfade in den Gültigkeitsbereich mit dem use-Schlüsselwort bringen

Es kann unbequem und repetitiv vorkommen, die Pfade zum Aufrufen von Funktionen auszuschreiben. In Listing 7-7 mussten wir unabhängig davon, ob wir den absoluten oder relativen Pfad zur add_to_waitlist-Funktion gewählt haben, jedes Mal, wenn wir add_to_waitlist aufrufen wollten, auch front_of_house und hosting angeben. Glücklicherweise gibt es einen Weg, diesen Prozess zu vereinfachen: Wir können einmal einen Kurzschluss für einen Pfad mit dem use-Schlüsselwort erstellen und dann den kürzeren Namen überall im Gültigkeitsbereich verwenden.

In Listing 7-11 bringen wir das crate::front_of_house::hosting-Modul in den Gültigkeitsbereich der eat_at_restaurant-Funktion, sodass wir nur hosting::add_to_waitlist angeben müssen, um die add_to_waitlist-Funktion in eat_at_restaurant aufzurufen.

Dateiname: src/lib.rs

mod front_of_house {
    pub mod hosting {
        pub fn add_to_waitlist() {}
    }
}

use crate::front_of_house::hosting;

pub fn eat_at_restaurant() {
    hosting::add_to_waitlist();
}

Listing 7-11: Ein Modul in den Gültigkeitsbereich mit use bringen

Das Hinzufügen von use und eines Pfads in einem Gültigkeitsbereich ähnelt dem Erstellen eines Symbolischen Links im Dateisystem. Indem wir use crate::front_of_house::hosting im Crate-Root hinzufügen, ist hosting jetzt ein gültiger Name in diesem Gültigkeitsbereich, genau so, als wäre das hosting-Modul im Crate-Root definiert worden. Pfade, die mit use in den Gültigkeitsbereich gebracht werden, überprüfen auch die Privatsphäre, wie alle anderen Pfade.

Beachten Sie, dass use nur den Kurzschluss für den bestimmten Gültigkeitsbereich erstellt, in dem der use-Ausdruck vorkommt. Listing 7-12 verschiebt die eat_at_restaurant-Funktion in ein neues Kind-Modul namens customer, was dann ein anderer Gültigkeitsbereich als der use-Statement ist, sodass der Funktionskörper nicht kompilieren wird.

Dateiname: src/lib.rs

mod front_of_house {
    pub mod hosting {
        pub fn add_to_waitlist() {}
    }
}

use crate::front_of_house::hosting;

mod customer {
    pub fn eat_at_restaurant() {
        hosting::add_to_waitlist();
    }
}

Listing 7-12: Ein use-Statement gilt nur im Gültigkeitsbereich, in dem es steht.

Der Compilerfehler zeigt, dass der Kurzschluss innerhalb des customer-Moduls nicht mehr gilt:

error[E0433]: failed to resolve: use of undeclared crate or module `hosting`
  --> src/lib.rs:11:9
   |
11 |         hosting::add_to_waitlist();
   |         ^^^^^^^ use of undeclared crate or module `hosting`

warning: unused import: `crate::front_of_house::hosting`
 --> src/lib.rs:7:5
  |
7 | use crate::front_of_house::hosting;
  |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  |
  = note: `#[warn(unused_imports)]` on by default

Beachten Sie, dass es auch eine Warnung gibt, dass der use in seinem Gültigkeitsbereich nicht mehr verwendet wird! Um dieses Problem zu beheben, verschieben Sie den use ebenfalls innerhalb des customer-Moduls oder verweisen Sie auf den Kurzschluss im Elternmodul mit super::hosting innerhalb des Kind-Moduls customer.

Schöne use-Pfade erstellen

In Listing 7-11 hast du dich vielleicht gefragt, warum wir use crate::front_of_house::hosting angegeben haben und dann in eat_at_restaurant hosting::add_to_waitlist aufgerufen haben, anstatt den use-Pfad bis zur add_to_waitlist-Funktion hinzuschreiben, um das gleiche Ergebnis zu erzielen, wie in Listing 7-13.

Dateiname: src/lib.rs

mod front_of_house {
    pub mod hosting {
        pub fn add_to_waitlist() {}
    }
}

use crate::front_of_house::hosting::add_to_waitlist;

pub fn eat_at_restaurant() {
    add_to_waitlist();
}

Listing 7-13: Die add_to_waitlist-Funktion mit use in den Gültigkeitsbereich bringen, was nicht idiomatisch ist

Obwohl sowohl Listing 7-11 als auch Listing 7-13 die gleiche Aufgabe erfüllen, ist Listing 7-11 die idiomatische Weise, eine Funktion mit use in den Gültigkeitsbereich zu bringen. Das Bringen des Elternmoduls der Funktion mit use in den Gültigkeitsbereich bedeutet, dass wir das Elternmodul angeben müssen, wenn wir die Funktion aufrufen. Das Angabe des Elternmoduls beim Funktionsaufruf macht klar, dass die Funktion nicht lokal definiert ist, während die Wiederholung des vollen Pfads gleichzeitig minimiert wird. Der Code in Listing 7-13 ist unklar, wo add_to_waitlist definiert ist.

Andererseits ist es idiomatisch, den vollen Pfad anzugeben, wenn man Structs, Enums und andere Elemente mit use einführt. Listing 7-14 zeigt die idiomatische Weise, die HashMap-Struktur der Standardbibliothek in den Gültigkeitsbereich eines Binärcrates zu bringen.

Dateiname: src/main.rs

use std::collections::HashMap;

fn main() {
    let mut map = HashMap::new();
    map.insert(1, 2);
}

Listing 7-14: HashMap auf idiomatische Weise in den Gültigkeitsbereich bringen

Es gibt keinen starken Grund hinter dieser Idiomatik: Es ist einfach die Konvention, die sich herausgebildet hat, und die Leute sind daran gewöhnt, Rust-Code so zu lesen und zu schreiben.

Die Ausnahme von dieser Idiomatik besteht darin, wenn wir zwei Elemente mit demselben Namen mit use-Statements in den Gültigkeitsbereich bringen, weil Rust das nicht erlaubt. Listing 7-15 zeigt, wie man zwei Result-Typen mit demselben Namen, aber unterschiedlichen Elternmodulen, in den Gültigkeitsbereich bringt und wie man auf sie verweist.

Dateiname: src/lib.rs

use std::fmt;
use std::io;

fn function1() -> fmt::Result {
    --snip--
}

fn function2() -> io::Result<()> {
    --snip--
}

Listing 7-15: Zwei Typen mit demselben Namen in denselben Gültigkeitsbereich bringen erfordert die Verwendung ihrer Elternmodule.

Wie du siehst, unterscheidet die Verwendung der Elternmodule die beiden Result-Typen. Wenn wir stattdessen use std::fmt::Result und use std::io::Result angegeben hätten, würden wir zwei Result-Typen im selben Gültigkeitsbereich haben, und Rust würde nicht wissen, welchen wir meinen, wenn wir Result verwenden.

Neue Namen mit dem as-Schlüsselwort angeben

Es gibt eine weitere Lösung für das Problem, zwei Typen mit demselben Namen mit use in denselben Gültigkeitsbereich zu bringen: Nach dem Pfad können wir as und einen neuen lokalen Namen, oder Alias, für den Typ angeben. Listing 7-16 zeigt eine andere Möglichkeit, den Code aus Listing 7-15 zu schreiben, indem wir einen der beiden Result-Typen mit as umbenennen.

Dateiname: src/lib.rs

use std::fmt::Result;
use std::io::Result as IoResult;

fn function1() -> Result {
    --snip--
}

fn function2() -> IoResult<()> {
    --snip--
}

Listing 7-16: Ein Typ umbenennen, wenn er mit dem as-Schlüsselwort in den Gültigkeitsbereich gebracht wird

In der zweiten use-Anweisung haben wir für den std::io::Result-Typ den neuen Namen IoResult gewählt, der nicht mit dem Result aus std::fmt kollidieren wird, das wir ebenfalls in den Gültigkeitsbereich gebracht haben. Listing 7-15 und Listing 7-16 gelten als idiomatisch, also ist die Wahl Ihnen überlassen!

Namen mit pub use erneut exportieren

Wenn wir einen Namen mit dem use-Schlüsselwort in den Gültigkeitsbereich bringen, ist der Name, der im neuen Gültigkeitsbereich verfügbar ist, privat. Um es dem Code zu ermöglichen, der unseren Code aufruft, auf diesen Namen so zu verweisen, als wäre er in dem Gültigkeitsbereich des Codes definiert, können wir pub und use kombinieren. Diese Technik wird als erneutes Exportieren bezeichnet, weil wir ein Element in den Gültigkeitsbereich bringen, aber dieses Element auch anderen zur Verfügung stellen, damit sie es in ihren Gültigkeitsbereich bringen können.

Listing 7-17 zeigt den Code aus Listing 7-11, wobei der use im Root-Modul in pub use geändert wurde.

Dateiname: src/lib.rs

mod front_of_house {
    pub mod hosting {
        pub fn add_to_waitlist() {}
    }
}

pub use crate::front_of_house::hosting;

pub fn eat_at_restaurant() {
    hosting::add_to_waitlist();
}

Listing 7-17: Einen Namen für jeden Code verfügbar machen, der ihn aus einem neuen Gültigkeitsbereich mit pub use verwenden kann

Bevor diese Änderung erfolgte, hätte externer Code die add_to_waitlist-Funktion aufrufen müssen, indem er den Pfad restaurant::front_of_house::hosting::add_to_waitlist() verwendet. Jetzt, da dieses pub use das hosting-Modul aus dem Root-Modul erneut exportiert hat, kann externer Code stattdessen den Pfad restaurant::hosting::add_to_waitlist() verwenden.

Das erneute Exportieren ist nützlich, wenn die interne Struktur Ihres Codes von der Art der Denkweise der Programmierer unterscheidet, die Ihren Code aufrufen. Beispielsweise denken die Menschen, die das Restaurant betreiben, an "Vorderseite des Hauses" und "Hinterseite des Hauses" im Rahmen dieser Restaurant-Metapher. Aber Kunden, die ein Restaurant besuchen, werden wahrscheinlich nicht in diesen Begriffen über die Teile des Restaurants nachdenken. Mit pub use können wir unseren Code mit einer Struktur schreiben, aber eine andere Struktur offenbaren. Dadurch wird unsere Bibliothek für Programmierer, die an der Bibliothek arbeiten, und Programmierer, die die Bibliothek aufrufen, gut strukturiert. Wir werden in "Exporting a Convenient Public API with pub use" ein weiteres Beispiel für pub use und wie es die Dokumentation Ihres Crates beeinflusst, betrachten.

Externe Pakete verwenden

Im zweiten Kapitel haben wir ein Zahlenratespielprojekt programmiert, bei dem wir ein externes Paket namens rand verwendet haben, um Zufallszahlen zu erhalten. Um rand in unserem Projekt zu verwenden, haben wir diese Zeile in Cargo.toml hinzugefügt:

Dateiname: Cargo.toml

rand = "0.8.5"

Das Hinzufügen von rand als Abhängigkeit in Cargo.toml veranlasst Cargo, das rand-Paket und alle Abhängigkeiten von https://crates.io herunterzuladen und rand unserem Projekt zur Verfügung zu stellen.

Dann, um die rand-Definitionen in den Gültigkeitsbereich unseres Pakets zu bringen, haben wir eine use-Zeile hinzugefügt, die mit dem Namen des Crates, rand, beginnt, und die Elemente aufgelistet, die wir in den Gültigkeitsbereich bringen wollten. Denken Sie daran, dass wir im Abschnitt "Generating a Random Number" das Rng-Trait in den Gültigkeitsbereich gebracht und die rand::thread_rng-Funktion aufgerufen haben:

use rand::Rng;

fn main() {
    let secret_number = rand::thread_rng().gen_range(1..=100);
}

Mitglieder der Rust-Community haben viele Pakete auf https://crates.io zur Verfügung gestellt, und das Einbinden eines beliebigen davon in Ihr Paket erfordert dieselben Schritte: Es wird in der Cargo.toml-Datei Ihres Pakets aufgelistet und use verwendet, um Elemente aus ihren Crates in den Gültigkeitsbereich zu bringen.

Beachten Sie, dass die Standardbibliothek std ebenfalls ein Crate ist, das extern zu unserem Paket ist. Da die Standardbibliothek mit der Rust-Sprache ausgeliefert wird, müssen wir Cargo.toml nicht ändern, um std einzuschließen. Aber wir müssen sie mit use referenzieren, um Elemente von dort in den Gültigkeitsbereich unseres Pakets zu bringen. Beispielsweise würden wir für HashMap diese Zeile verwenden:

use std::collections::HashMap;

Dies ist ein absoluter Pfad, der mit std beginnt, dem Namen des Crates der Standardbibliothek.

Verwendung geschachtelter Pfade, um lange use-Listen zu vereinfachen

Wenn wir mehrere Elemente verwenden, die in demselben Crate oder demselben Modul definiert sind, kann das Auflisten jedes Elements auf einer eigenen Zeile viel vertikalen Platz in unseren Dateien beanspruchen. Beispielsweise bringen diese beiden use-Anweisungen, die wir im Zahlenratespiel in Listing 2-4 hatten, Elemente aus std in den Gültigkeitsbereich:

Dateiname: src/main.rs

--snip--
use std::cmp::Ordering;
use std::io;
--snip--

Stattdessen können wir geschachtelte Pfade verwenden, um die gleichen Elemente in einen einzigen Zeile in den Gültigkeitsbereich zu bringen. Dazu geben wir den gemeinsamen Teil des Pfads an, gefolgt von zwei Doppelpunkten, und dann geschweifte Klammern um eine Liste der unterschiedlichen Teile des Pfads, wie in Listing 7-18 gezeigt.

Dateiname: src/main.rs

--snip--
use std::{cmp::Ordering, io};
--snip--

Listing 7-18: Ein geschachtelter Pfad angeben, um mehrere Elemente mit demselben Präfix in den Gültigkeitsbereich zu bringen

In größeren Programmen kann das Einführen vieler Elemente aus demselben Crate oder Modul mithilfe geschachtelter Pfade die Anzahl der erforderlichen separaten use-Anweisungen erheblich reduzieren!

Wir können einen geschachtelten Pfad auf jeder Ebene eines Pfads verwenden, was nützlich ist, wenn zwei use-Anweisungen kombiniert werden, die einen gemeinsamen Unterpfad haben. Beispielsweise zeigt Listing 7-19 zwei use-Anweisungen: eine, die std::io in den Gültigkeitsbereich bringt, und eine, die std::io::Write in den Gültigkeitsbereich bringt.

Dateiname: src/lib.rs

use std::io;
use std::io::Write;

Listing 7-19: Zwei use-Anweisungen, wobei eine ein Unterpfad der anderen ist

Der gemeinsame Teil dieser beiden Pfade ist std::io, und das ist der vollständige erste Pfad. Um diese beiden Pfade zu einer einzigen use-Anweisung zu vereinigen, können wir self im geschachtelten Pfad verwenden, wie in Listing 7-20 gezeigt.

Dateiname: src/lib.rs

use std::io::{self, Write};

Listing 7-20: Die Pfade aus Listing 7-19 zu einer einzigen use-Anweisung kombinieren

Diese Zeile bringt std::io und std::io::Write in den Gültigkeitsbereich.

Der Glob-Operator

Wenn wir alle öffentlichen Elemente, die in einem Pfad definiert sind, in den Gültigkeitsbereich bringen möchten, können wir diesen Pfad angeben, gefolgt vom *-Glob-Operator:

use std::collections::*;

Diese use-Anweisung bringt alle öffentlichen Elemente, die in std::collections definiert sind, in den aktuellen Gültigkeitsbereich. Seien Sie bei der Verwendung des Glob-Operators vorsichtig! Der Glob-Operator kann es schwieriger machen, zu erkennen, welche Namen im Gültigkeitsbereich sind und wo ein in Ihrem Programm verwendeter Name definiert wurde.

Der Glob-Operator wird häufig bei Tests verwendet, um alles, was getestet werden soll, in das tests-Modul zu bringen; wir werden darüber in "How to Write Tests" sprechen. Der Glob-Operator wird auch manchmal als Teil des Präambel-Musters verwendet; siehe die Standardbibliotheksdokumentation für weitere Informationen zu diesem Muster.

Zusammenfassung

Herzlichen Glückwunsch! Sie haben das Lab "Bringing Paths Into Scope With the Use Keyword" abgeschlossen. Sie können in LabEx weitere Labs absolvieren, um Ihre Fähigkeiten zu verbessern.