Module in Rust
Bisher stand jedes Beispiel in einer einzigen Datei main.rs. Für kleine Programme ist das in Ordnung. Echte Projekte teilen ihren Code aber in sinnvolle Teile auf. Dafür hat Rust das Modulsystem – mit mod, pub und use.
Ein Modul definieren
Abschnitt betitelt „Ein Modul definieren“Ein Modul ist ein benannter Block, der zusammengehörigen Code bündelt:
mod math { pub fn add(a: i32, b: i32) -> i32 { a + b }}
fn main() { let sum = math::add(2, 3); println!("{sum}");}Ausgabe:
5Zwei Dinge fallen auf: Du rufst die Funktion mit math::add(...) auf und benutzt den Modulnamen dabei als Pfad. Und die Funktion ist mit pub markiert. Ohne pub wäre sie von außerhalb des Moduls nicht erreichbar.
Alles ist standardmäßig privat
Abschnitt betitelt „Alles ist standardmäßig privat“Das solltest du dir merken, weil es viele überrascht: Der Inhalt eines Moduls ist standardmäßig privat. Wenn du im Beispiel oben pub entfernst, lässt sich der Code nicht mehr kompilieren:
mod math { fn add(a: i32, b: i32) -> i32 { // kein `pub` a + b }}
fn main() { let sum = math::add(2, 3); // ❌ Fehler: die Funktion `add` ist privat println!("{sum}");}Alles, was Code außerhalb des Moduls benutzen soll, musst du ausdrücklich mit pub markieren. Das ist Absicht: So kann ein Modul seine internen Hilfsfunktionen verstecken und nur die Teile zeigen, die als öffentliche Schnittstelle (API) gedacht sind.
Verschachtelte Module
Abschnitt betitelt „Verschachtelte Module“Module können andere Module enthalten. So entsteht in größeren Projekten eine Baumstruktur:
mod shapes { pub mod circle { pub fn area(radius: f64) -> f64 { 3.14159 * radius * radius } }}
fn main() { let area = shapes::circle::area(2.0); println!("{area}");}use – lange Pfade abkürzen
Abschnitt betitelt „use – lange Pfade abkürzen“Jedes Mal shapes::circle::area(...) zu schreiben, wird schnell lästig. Mit use holst du einen Pfad in den aktuellen Gültigkeitsbereich (Scope) und kannst ihn dann direkt benutzen:
mod shapes { pub mod circle { pub fn area(radius: f64) -> f64 { 3.14159 * radius * radius } }}
use shapes::circle;
fn main() { let area = circle::area(2.0); // kürzer als shapes::circle::area println!("{area}");}Eigentlich hast du use schon benutzt: Es ist dasselbe Schlüsselwort wie auf der Seite über HashMap (use std::collections::HashMap;).
Module auf mehrere Dateien aufteilen
Abschnitt betitelt „Module auf mehrere Dateien aufteilen“In den Beispielen oben steht alles in einer Datei, weil der Rust Playground das so verlangt. In einem echten Projekt auf deinem Rechner bekommt meist jedes Modul seine eigene Datei. Ein Projekt mit einem Modul math sieht typischerweise so aus:
src/├── main.rs└── math.rsmod math; // sagt Rust: Den Code dieses Moduls findest du in math.rs
fn main() { let sum = math::add(2, 3); println!("{sum}");}pub fn add(a: i32, b: i32) -> i32 { a + b}mod math; (mit Semikolon, ohne Rumpf) weist Rust an, den Inhalt des Moduls aus der Datei math.rs im selben Ordner zu laden. Dieses Muster brauchst du, sobald dein Projekt über eine einzige Datei hinauswächst.
Übungen
Abschnitt betitelt „Übungen“1. Ein Modul für Temperaturen
Abschnitt betitelt „1. Ein Modul für Temperaturen“Schreib ein Modul namens convert mit zwei öffentlichen Funktionen: c_to_f (Celsius nach Fahrenheit) und f_to_c (umgekehrt). Gib aus main heraus 100°C sind 212°F und 212°F sind 100°C aus.
Tipp: Die Formeln sind c * 9.0 / 5.0 + 32.0 und (f - 32.0) * 5.0 / 9.0. Vergiss pub nicht, und ruf die Funktionen mit dem Modulnamen auf, etwa convert::c_to_f(100.0).
Lösung anzeigen
mod convert { pub fn c_to_f(c: f64) -> f64 { c * 9.0 / 5.0 + 32.0 }
pub fn f_to_c(f: f64) -> f64 { (f - 32.0) * 5.0 / 9.0 }}
fn main() { println!("100°C sind {}°F", convert::c_to_f(100.0)); println!("212°F sind {}°C", convert::f_to_c(212.0));}Ausgabe:
100°C sind 212°F212°F sind 100°CBeide Funktionen sind pub. Deshalb kann main sie aufrufen, obwohl es außerhalb des Moduls liegt. Entfernst du ein pub, sagt dir der Compiler, dass diese Funktion privat ist.
2. Eine private Hilfsfunktion
Abschnitt betitelt „2. Eine private Hilfsfunktion“Schreib ein verschachteltes Modul school::grades mit einer öffentlichen Funktion letter(score: u32) -> char. Sie gibt 'A' für 90 und mehr zurück, 'B' für 80 und mehr und sonst 'C'. Schreib in grades außerdem eine private Hilfsfunktion is_at_least(score: u32, min: u32) -> bool, die letter benutzt. Hol school::grades mit use in den Scope und gib dann die Note für 95, 85 und 70 aus.
Tipp: Sowohl das innere mod grades in school als auch fn letter brauchen pub, is_at_least aber nicht. Code im selben Modul kann private Funktionen immer aufrufen.
Lösung anzeigen
mod school { pub mod grades { pub fn letter(score: u32) -> char { if is_at_least(score, 90) { 'A' } else if is_at_least(score, 80) { 'B' } else { 'C' } }
// privat: nur Code innerhalb von `grades` kann das aufrufen fn is_at_least(score: u32, min: u32) -> bool { score >= min } }}
use school::grades;
fn main() { for score in [95, 85, 70] { println!("{score} -> {}", grades::letter(score)); }}Ausgabe:
95 -> A85 -> B70 -> Cletter kann is_at_least aufrufen, weil beide im selben Modul liegen. Aus main heraus würde grades::is_at_least(95, 90) mit „function is_at_least is private“ scheitern (die Funktion ist privat). Genau darum geht es: Das Modul zeigt nach außen eine kleine öffentliche API und behält seine Hilfsfunktionen für sich.
Zusammenfassung
Abschnitt betitelt „Zusammenfassung“mod name { ... }bündelt zusammengehörigen Code in einem benannten Modul.- Alles in einem Modul ist standardmäßig privat. Mit
pubmachst du es außerhalb des Moduls sichtbar. useholt einen Pfad in den Scope, damit du ihn nicht jedes Mal komplett ausschreiben musst.- In einem Projekt mit mehreren Dateien lädt
mod name;(ohne Rumpf) den Code des Moduls aus der passenden Datei. - Code in einem Modul kann dessen private Elemente immer benutzen. Halte Hilfsfunktionen also privat und mach nur sichtbar, was Aufrufer wirklich brauchen.
Kurzer Check
Abschnitt betitelt „Kurzer Check“Kurzer Check
1. Sind Elemente in einem mod standardmäßig öffentlich oder privat?
2. Wie sagst du Rust, dass es den Code eines Moduls aus math.rs laden soll, statt ihn direkt hinzuschreiben?
Punkte: 0 / 2
Weiterlesen
Abschnitt betitelt „Weiterlesen“- Pakete, Crates und Module – Das Rust-Buch: das offizielle Kapitel über Pakete, Crates und Module und wie sie zusammenspielen.
- Gültigkeitsbereich und Sichtbarkeit mit Modulen steuern – Das Rust-Buch: ein durchgearbeitetes Beispiel für einen Modulbaum, mit einem praktischen Spickzettel der Regeln.
- Module in verschiedene Dateien aufteilen – Das Rust-Buch: die Aufteilung auf mehrere Dateien im Detail, inklusive Ordnern für verschachtelte Module.
- Modules – Rust by Example (auf Englisch): ausführbare Beispiele zu Sichtbarkeit,
use,superundself. - Visibility and privacy – The Rust Reference (auf Englisch): die genauen Regeln, auch zu
pub(crate)für „öffentlich, aber nur in meinem Crate“.