Einführung
Willkommen zu Packages and Crates. Dieser Lab ist ein Teil des Rust Buchs. Du kannst deine Rust-Fähigkeiten in LabEx üben.
In diesem Lab werden wir uns mit Packages und Crates befassen, wobei ein Crate die kleinste Code-Einheit ist, die der Rust-Compiler betrachtet und entweder ein binäres Crate oder ein Bibliothekscrate sein kann, und ein Package eine Sammlung von einem oder mehreren Crates ist, die eine bestimmte Funktionalität bietet.
Packages und Crates
Die ersten Teile des Modulsystems, das wir behandeln werden, sind Packages und Crates.
Ein Crate ist die kleinste Menge an Code, die der Rust-Compiler gleichzeitig betrachtet. Auch wenn Sie rustc statt cargo ausführen und eine einzelne Quellcode-Datei übergeben (wie wir es schon in "Schreiben und Ausführen eines Rust-Programms" getan haben), betrachtet der Compiler diese Datei als ein Crate. Crates können Module enthalten, und die Module können in anderen Dateien definiert sein, die mit dem Crate kompiliert werden, wie wir in den kommenden Abschnitten sehen werden.
Ein Crate kann in einer von zwei Formen vorliegen: ein binäres Crate oder ein Bibliothekscrate. Binäre Crates sind Programme, die Sie zu einem ausführbaren Programm kompilieren können, das Sie ausführen können, wie z. B. ein Befehlszeilenprogramm oder ein Server. Jeder muss eine Funktion namens main haben, die definiert, was passiert, wenn das ausführbare Programm ausgeführt wird. Alle Crates, die wir bisher erstellt haben, waren binäre Crates.
Bibliothekscrates haben keine main-Funktion und kompilieren nicht zu einem ausführbaren Programm. Stattdessen definieren sie Funktionalität, die mit mehreren Projekten geteilt werden soll. Beispielsweise bietet das rand-Crate, das wir im zweiten Kapitel verwendet haben, Funktionalität, um Zufallszahlen zu generieren. In den meisten Fällen, wenn Rust-Entwickler "Crate" sagen, meinen sie Bibliothekscrate, und sie verwenden "Crate" synonym mit dem allgemeinen Programmierkonzept einer "Bibliothek".
Die Crate-Wurzel ist eine Quellcode-Datei, von der der Rust-Compiler ausgeht und die das Wurzelmodul Ihres Crates bildet (wir werden Module im Abschnitt "Definieren von Modulen zur Kontrolle von Bereich und Privatsphäre" im Detail erklären).
Ein Package ist ein Bund von einem oder mehreren Crates, der eine bestimmte Funktionalität bietet. Ein Package enthält eine Cargo.toml-Datei, die beschreibt, wie diese Crates gebaut werden sollen. Cargo ist tatsächlich ein Package, das das binäre Crate für das Befehlszeilenwerkzeug enthält, das Sie bisher verwendet haben, um Ihren Code zu bauen. Das Cargo-Package enthält auch ein Bibliothekscrate, auf das das binäre Crate angewiesen ist. Andere Projekte können auf das Cargo-Bibliothekscrate zurückgreifen, um dieselbe Logik zu verwenden, die das Cargo-Befehlszeilenwerkzeug verwendet.
Ein Crate kann in einer von zwei Formen vorliegen: ein binäres Crate oder ein Bibliothekscrate. Ein Package kann beliebig viele binäre Crates enthalten, aber höchstens nur ein Bibliothekscrate. Ein Package muss mindestens ein Crate enthalten, egal ob es sich um ein Bibliothekscrate oder ein binäres Crate handelt.
Lassen Sie uns durchgehen, was passiert, wenn wir ein Package erstellen. Zunächst geben wir den Befehl cargo new my-project ein:
$ cargo new my-project
Created binary (application) `my-project` package
$ ls my-project
Cargo.toml
src
$ ls my-project/src
main.rs
Nachdem wir cargo new my-project ausgeführt haben, verwenden wir ls, um zu sehen, was Cargo erstellt. Im Projektverzeichnis befindet sich eine Cargo.toml-Datei, die uns ein Package gibt. Es gibt auch ein src-Verzeichnis, das main.rs enthält. Öffnen Sie Cargo.toml in Ihrem Texteditor und bemerken Sie, dass src/main.rs nicht erwähnt wird. Cargo folgt der Konvention, dass src/main.rs die Crate-Wurzel eines binären Crates mit dem gleichen Namen wie das Package ist. Ebenso weiß Cargo, dass wenn das Package-Verzeichnis src/lib.rs enthält, das Package ein Bibliothekscrate mit dem gleichen Namen wie das Package enthält und src/lib.rs seine Crate-Wurzel ist. Cargo übergibt die Crate-Wurzel-Dateien an rustc, um die Bibliothek oder das binäre Programm zu bauen.
Hier haben wir ein Package, das nur src/main.rs enthält, was bedeutet, dass es nur ein binäres Crate namens my-project enthält. Wenn ein Package src/main.rs und src/lib.rs enthält, hat es zwei Crates: ein binäres und ein Bibliothekscrate, beide mit dem gleichen Namen wie das Package. Ein Package kann mehrere binäre Crates haben, indem Sie Dateien im src/bin-Verzeichnis platzieren: jede Datei wird ein separates binäres Crate sein.
Modules Cheat Sheet
Bevor wir auf die Details von Modulen und Pfaden zugehen, geben wir hier einen schnellen Überblick darüber, wie sich Module, Pfade, das
use-Schlüsselwort und daspub-Schlüsselwort im Compiler verhalten und wie die meisten Entwickler ihren Code organisieren. Wir werden in diesem Kapitel Beispiele für jede dieser Regeln durchgehen, aber hier ist ein guter Bezugspunkt, um sich daran zu erinnern, wie die Module funktionieren.
- Starten von der Crate-Wurzel: Wenn ein Crate kompiliert wird, sucht der Compiler zunächst in der Crate-Wurzel-Datei (gewöhnlich
src/lib.rsfür ein Bibliothekscrate odersrc/main.rsfür ein binäres Crate) nach Code, der kompiliert werden soll.- Deklarieren von Modulen: In der Crate-Wurzel-Datei können Sie neue Module deklarieren; sagen Sie, Sie deklarieren ein "garden"-Modul mit
mod garden;. Der Compiler wird den Code des Moduls an diesen Stellen suchen:- Inline, innerhalb geschweifter Klammern, die das Semikolon nach
mod gardenersetzen- In der Datei
src/garden.rs- In der Datei
src/garden/mod.rs- Deklarieren von Untermodulen: In jeder Datei außer der Crate-Wurzel können Sie Untermodule deklarieren. Beispielsweise können Sie
mod vegetables;insrc/garden.rsdeklarieren. Der Compiler wird den Code des Untermoduls innerhalb des Verzeichnisses suchen, das für das übergeordnete Modul benannt ist, an diesen Stellen:- Inline, direkt nach
mod vegetables, innerhalb geschweifter Klammern statt des Semikolons- In der Datei
src/garden/vegetables.rs- In der Datei
src/garden/vegetables/mod.rs- Pfade zu Code in Modulen: Wenn ein Modul Teil Ihres Crates ist, können Sie auf den Code in diesem Modul von überall anderen im selben Crate zugreifen, solange die Privatsphäre-Regeln es erlauben, indem Sie den Pfad zum Code verwenden. Beispielsweise würde ein
Asparagus-Typ im Garten-Getreide-Modul beicrate::garden::vegetables::Asparagusgefunden werden.- Privat vs. öffentlich: Der Code innerhalb eines Moduls ist standardmäßig für seine übergeordneten Module privat. Um ein Modul öffentlich zu machen, deklarieren Sie es mit
pub modanstelle vonmod. Um auch die Elemente innerhalb eines öffentlichen Moduls öffentlich zu machen, verwenden Siepubvor ihrer Deklaration.- Das use-Schlüsselwort: Innerhalb eines Bereichs erzeugt das
use-Schlüsselwort Kurzschlüsse zu Elementen, um die Wiederholung langer Pfade zu reduzieren. In jedem Bereich, in dem aufcrate::garden::vegetables::Asparagusverwiesen werden kann, können Sie einen Kurzschluss mituse crate::garden::vegetables::Asparagus;erstellen, und ab dann müssen Sie nurAsparagusschreiben, um diesen Typ im Bereich zu verwenden.Hier erstellen wir ein binäres Crate namens
backyard, das diese Regeln veranschaulicht. Das Verzeichnis des Crates, ebenfalls benanntbackyard, enthält diese Dateien und Verzeichnisse:backyard ├── Cargo.lock ├── Cargo.toml └── src ├── garden │ └── vegetables.rs ├── garden.rs └── main.rsDie Crate-Wurzel-Datei in diesem Fall ist
src/main.rs, und sie enthält:use crate::garden::vegetables::Asparagus; pub mod garden; fn main() { let plant = Asparagus {}; println!("I'm growing {:?}!", plant); }Die Zeile
pub mod garden;sagt dem Compiler, den Code einzubeziehen, den er insrc/garden.rsfindet, der ist:pub mod vegetables;Hier bedeutet
pub mod vegetables;, dass auch der Code insrc/garden/vegetables.rseingeschlossen wird. Der Code ist:#[derive(Debug)] pub struct Asparagus {}Lassen Sie uns jetzt in die Details dieser Regeln eintauchen und sie in Aktion demonstrieren!
Zusammenfassung
Herzlichen Glückwunsch! Sie haben das Lab zu Packages und Crates abgeschlossen. Sie können in LabEx weitere Labs absolvieren, um Ihre Fähigkeiten zu verbessern.