Das Erkunden von Cargo Workspaces in Rust

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 Cargo Workspaces. Dieser Lab ist ein Teil des Rust Buchs. Du kannst deine Rust-Fähigkeiten in LabEx üben.

In diesem Lab werden wir die Workspaces-Funktion von Cargo erkunden, die es hilft, mehrere miteinander verbundene Pakete, die parallel entwickelt werden, zu verwalten, indem ein Paket in mehrere Bibliothekskraten unterteilt wird.


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/DataTypesGroup -.-> rust/integer_types("Integer Types") 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-100429{{"Das Erkunden von Cargo Workspaces in Rust"}} rust/integer_types -.-> lab-100429{{"Das Erkunden von Cargo Workspaces in Rust"}} rust/function_syntax -.-> lab-100429{{"Das Erkunden von Cargo Workspaces in Rust"}} rust/expressions_statements -.-> lab-100429{{"Das Erkunden von Cargo Workspaces in Rust"}} rust/method_syntax -.-> lab-100429{{"Das Erkunden von Cargo Workspaces in Rust"}} end

Cargo Workspaces

Im Kapitel 12 haben wir ein Paket gebaut, das einen Binärkraten und einen Bibliothekskraten enthielt. Wenn sich Ihr Projekt entwickelt, könnten Sie feststellen, dass der Bibliothekskraten immer größer wird und Sie möchten Ihr Paket weiter in mehrere Bibliothekskrate aufteilen. Cargo bietet eine Funktion namens Workspaces, die Ihnen helfen kann, mehrere miteinander verbundene Pakete zu verwalten, die parallel entwickelt werden.

Ein Arbeitsbereich erstellen

Ein Arbeitsbereich ist eine Gruppe von Paketen, die die gleiche Cargo.lock und Ausgabeverzeichnis teilen. Lassen Sie uns ein Projekt mit einem Arbeitsbereich erstellen - wir werden einfache Code verwenden, damit wir uns auf die Struktur des Arbeitsbereichs konzentrieren können. Es gibt mehrere Möglichkeiten, einen Arbeitsbereich zu strukturieren, daher zeigen wir nur eine häufige Methode. Wir werden einen Arbeitsbereich haben, der eine Binärdatei und zwei Bibliotheken enthält. Die Binärdatei, die die Hauptfunktionalität bereitstellen wird, wird von den beiden Bibliotheken abhängen. Eine Bibliothek wird eine add_one-Funktion und die andere Bibliothek eine add_two-Funktion bereitstellen. Diese drei Kraten werden Teil des gleichen Arbeitsbereichs sein. Wir beginnen, indem wir ein neues Verzeichnis für den Arbeitsbereich erstellen:

mkdir add
cd add

Als nächstes erstellen wir in das Verzeichnis add die Datei Cargo.toml, die den gesamten Arbeitsbereich konfigurieren wird. Diese Datei wird keinen [package]-Abschnitt haben. Stattdessen beginnt sie mit einem [workspace]-Abschnitt, der es uns ermöglicht, Mitglieder zum Arbeitsbereich hinzuzufügen, indem wir den Pfad zum Paket mit unserem Binärkraten angeben; in diesem Fall ist dieser Pfad adder:

Dateiname: Cargo.toml

[workspace]

members = [
    "adder",
]

Als nächstes erstellen wir den Binärkraten adder, indem wir cargo new im Verzeichnis add ausführen:

$ cargo new adder
     Created binary (application) `adder` package

An diesem Punkt können wir den Arbeitsbereich erstellen, indem wir cargo build ausführen. Die Dateien in Ihrem Verzeichnis add sollten so aussehen:

├── Cargo.lock
├── Cargo.toml
├── adder
│   ├── Cargo.toml
│   └── src
│       └── main.rs
└── target

Der Arbeitsbereich hat ein target-Verzeichnis auf der obersten Ebene, in das die kompilierten Artefakte platziert werden; das adder-Paket hat kein eigenes target-Verzeichnis. Auch wenn wir cargo build aus dem adder-Verzeichnis ausführen würden, würden die kompilierten Artefakte immer noch in add/target landen, statt in add/adder/target. Cargo strukturiert das target-Verzeichnis in einem Arbeitsbereich so, weil die Kraten in einem Arbeitsbereich voneinander abhängen sollen. Wenn jedes Kraten sein eigenes target-Verzeichnis hätte, müsste jedes Kraten jedes andere Kraten im Arbeitsbereich erneut kompilieren, um die Artefakte in seinem eigenen target-Verzeichnis zu platzieren. Indem sie ein gemeinsames target-Verzeichnis teilen, können die Kraten unnötiges Neukompilieren vermeiden.

Das zweite Paket im Arbeitsbereich erstellen

Als nächstes erstellen wir in dem Arbeitsbereich ein weiteres Mitgliedspaket und nennen es add_one. Ändern Sie die oberste Ebene Cargo.toml, um den Pfad add_one in der members-Liste anzugeben:

Dateiname: Cargo.toml

[workspace]

members = [
    "adder",
    "add_one",
]

Dann erzeugen Sie einen neuen Bibliothekskraten namens add_one:

$ cargo new add_one --lib
Created library $(add_one) package

Ihr add-Verzeichnis sollte jetzt diese Verzeichnisse und Dateien haben:

├── Cargo.lock
├── Cargo.toml
├── add_one
│   ├── Cargo.toml
│   └── src
│       └── lib.rs
├── adder
│   ├── Cargo.toml
│   └── src
│       └── main.rs
└── target

In der Datei add_one/src/lib.rs fügen wir eine add_one-Funktion hinzu:

Dateiname: add_one/src/lib.rs

pub fn add_one(x: i32) -> i32 {
    x + 1
}

Jetzt können wir das adder-Paket mit unserer Binärdatei von dem add_one-Paket abhängig machen, das unsere Bibliothek enthält. Zunächst müssen wir eine Pfadabhängigkeit von add_one zu adder/Cargo.toml hinzufügen:

Dateiname: adder/Cargo.toml

[dependencies]
add_one = { path = "../add_one" }

Cargo nimmt nicht an, dass die Kraten in einem Arbeitsbereich voneinander abhängen werden, daher müssen wir die Abhängigkeitsbeziehungen explizit angeben.

Als nächstes verwenden wir die add_one-Funktion (aus dem add_one-Kraten) im adder-Kraten. Öffnen Sie die Datei adder/src/main.rs und fügen Sie oben eine use-Zeile hinzu, um den neuen add_one-Bibliothekskraten in den Geltungsbereich zu bringen. Ändern Sie dann die main-Funktion, um die add_one-Funktion aufzurufen, wie in Listing 14-7.

Dateiname: adder/src/main.rs

use add_one;

fn main() {
    let num = 10;
    println!(
        "Hello, world! {num} plus one is {}!",
        add_one::add_one(num)
    );
}

Listing 14-7: Verwenden des add_one-Bibliothekskratens aus dem adder-Kraten

Lassen Sie uns den Arbeitsbereich erstellen, indem wir cargo build im obersten Ebene add-Verzeichnis ausführen!

$ cargo build
   Compiling add_one v0.1.0 (file:///projects/add/add_one)
   Compiling adder v0.1.0 (file:///projects/add/adder)
    Finished dev [unoptimized + debuginfo] target(s) in 0.68s

Um das Binärpaket aus dem add-Verzeichnis auszuführen, können wir angeben, welches Paket im Arbeitsbereich wir ausführen möchten, indem wir das -p-Argument und den Paketnamen mit cargo run verwenden:

$ cargo run -p adder
    Finished dev [unoptimized + debuginfo] target(s) in 0.0s
     Running `target/debug/adder`
Hello, world! 10 plus one is 11!

Dies führt den Code in adder/src/main.rs aus, der von dem add_one-Kraten abhängt.

Abhängigkeit von einem externen Paket in einem Arbeitsbereich

Beachten Sie, dass der Arbeitsbereich nur eine Cargo.lock-Datei auf der obersten Ebene hat, anstatt in jedem Kratenverzeichnis eine Cargo.lock zu haben. Dadurch wird sichergestellt, dass alle Kraten die gleiche Version aller Abhängigkeiten verwenden. Wenn wir das rand-Paket zu den adder/Cargo.toml- und add_one/Cargo.toml-Dateien hinzufügen, wird Cargo beide auf eine Version von rand auflösen und das in der einen Cargo.lock aufzeichnen. Dass alle Kraten im Arbeitsbereich die gleichen Abhängigkeiten verwenden, bedeutet, dass die Kraten immer miteinander kompatibel sein werden. Fügen wir das rand-Kraten zur [dependencies]-Sektion in der add_one/Cargo.toml-Datei hinzu, so dass wir das rand-Kraten im add_one-Kraten verwenden können:

Dateiname: add_one/Cargo.toml

[dependencies]
rand = "0.8.5"

Wir können jetzt use rand; zur add_one/src/lib.rs-Datei hinzufügen, und das Erstellen des gesamten Arbeitsbereichs, indem wir cargo build im add-Verzeichnis ausführen, wird das rand-Kraten einbinden und kompilieren. Wir erhalten eine Warnung, weil wir nicht auf das rand verweisen, das wir in den Geltungsbereich gebracht haben:

$ cargo build
    Updating crates.io index
  Downloaded rand v0.8.5
   --snip--
   Compiling rand v0.8.5
   Compiling add_one v0.1.0 (file:///projects/add/add_one)
   Compiling adder v0.1.0 (file:///projects/add/adder)
    Finished dev [unoptimized + debuginfo] target(s) in 10.18s

Die oberste Ebene Cargo.lock enthält jetzt Informationen über die Abhängigkeit von add_one von rand. Allerdings können wir rand auch dann nicht in anderen Kraten im Arbeitsbereich verwenden, es sei denn, wir fügen rand auch zu ihren Cargo.toml-Dateien hinzu. Beispielsweise erhalten wir einen Fehler, wenn wir use rand; zur adder/src/main.rs-Datei für das adder-Paket hinzufügen:

$ cargo build
   --snip--
   Compiling adder v0.1.0 (file:///projects/add/adder)
error[E0432]: unresolved import `rand`
 --> adder/src/main.rs:2:5
  |
2 | use rand;
  |     ^^^^ no external crate `rand`

Um das zu beheben, bearbeiten Sie die Cargo.toml-Datei für das adder-Paket und geben an, dass rand auch eine Abhängigkeit für es ist. Das Erstellen des adder-Pakets wird rand zur Liste der Abhängigkeiten von adder in Cargo.lock hinzufügen, aber keine zusätzlichen Kopien von rand werden heruntergeladen. Cargo hat sichergestellt, dass jedes Kraten in jedem Paket im Arbeitsbereich, das das rand-Paket verwendet, die gleiche Version verwenden wird, spart uns Speicher und stellt sicher, dass die Kraten im Arbeitsbereich miteinander kompatibel sein werden.

Ein Test in einen Arbeitsbereich hinzufügen

Als weitere Verbesserung fügen wir einen Test der add_one::add_one-Funktion innerhalb des add_one-Kratens hinzu:

Dateiname: add_one/src/lib.rs

pub fn add_one(x: i32) -> i32 {
    x + 1
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn it_works() {
        assert_eq!(3, add_one(2));
    }
}

Führen Sie jetzt cargo test im obersten Ebene add-Verzeichnis aus. Wenn Sie cargo test in einem Arbeitsbereich wie diesem ausführen, werden die Tests für alle Kraten im Arbeitsbereich ausgeführt:

$ cargo test
   Compiling add_one v0.1.0 (file:///projects/add/add_one)
   Compiling adder v0.1.0 (file:///projects/add/adder)
    Finished test [unoptimized + debuginfo] target(s) in 0.27s
     Running unittests src/lib.rs (target/debug/deps/add_one-f0253159197f7841)

running 1 test
test tests::it_works... ok

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out;
finished in 0.00s

     Running unittests src/main.rs (target/debug/deps/adder-49979ff40686fa8e)

running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out;
finished in 0.00s

   Doc-tests add_one

running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out;
finished in 0.00s

Der erste Abschnitt der Ausgabe zeigt, dass der it_works-Test im add_one-Kraten bestanden hat. Der nächste Abschnitt zeigt, dass in dem adder-Kraten keine Tests gefunden wurden, und der letzte Abschnitt zeigt, dass in dem add_one-Kraten keine Dokumentationstests gefunden wurden.

Wir können auch die Tests für einen bestimmten Kraten in einem Arbeitsbereich aus dem obersten Ebene Verzeichnis ausführen, indem wir das -p-Flag verwenden und den Namen des Kratens angeben, für den wir die Tests ausführen möchten:

$ cargo test -p add_one
    Finished test [unoptimized + debuginfo] target(s) in 0.00s
     Running unittests src/lib.rs (target/debug/deps/add_one-b3235fea9a156f74)

running 1 test
test tests::it_works... ok

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out;
finished in 0.00s

   Doc-tests add_one

running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out;
finished in 0.00s

Diese Ausgabe zeigt, dass cargo test nur die Tests für den add_one-Kraten ausgeführt hat und die adder-Kraten-Tests nicht ausgeführt hat.

Wenn Sie die Kraten im Arbeitsbereich auf https://crates.io veröffentlichen, müssen Sie jedes Kraten im Arbeitsbereich separat veröffentlichen. Wie cargo test können wir ein bestimmtes Kraten in unserem Arbeitsbereich veröffentlichen, indem wir das -p-Flag verwenden und den Namen des Kratens angeben, das wir veröffentlichen möchten.

Für zusätzliche Übung fügen Sie einen add_two-Kraten zu diesem Arbeitsbereich auf eine ähnliche Weise wie den add_one-Kraten hinzu!

Wenn sich Ihr Projekt erweitert, sollten Sie einen Arbeitsbereich in Betracht ziehen: Er bietet einfachere zu verstehende, kleinere, individuelle Komponenten als ein großer Codeblock. Darüber hinaus kann das Zusammenhalten der Kraten in einem Arbeitsbereich die Koordination zwischen den Kraten erleichtern, wenn sie oft gleichzeitig geändert werden.

Zusammenfassung

Herzlichen Glückwunsch! Sie haben das Cargo Workspaces-Labor abgeschlossen. Sie können in LabEx weitere Labs absolvieren, um Ihre Fähigkeiten zu verbessern.