Kurz: Mit mod gliederst du Code. Alles ist standardmäßig privat; pub macht es sichtbar.
Teil des Kurses Rust
Module
Mit mod gliederst du Code. Alles ist standardmäßig privat; pub macht es sichtbar.
mod geometrie {
pub const PI: f64 = 3.14159;
pub struct Kreis {
pub radius: f64,
id: u32, // privat
}
impl Kreis {
pub fn neu(radius: f64) -> Self { Kreis { radius, id: 1 } }
pub fn flaeche(&self) -> f64 { PI * self.radius * self.radius }
pub fn id(&self) -> u32 { self.id }
}
pub mod hilfe {
pub fn runde(x: f64) -> f64 { (x * 100.0).round() / 100.0 }
}
}
use geometrie::{hilfe::runde, Kreis};
fn main() {
let k = Kreis::neu(2.0);
println!("{} {}", runde(k.flaeche()), k.id());
println!("{}", geometrie::PI);
}Ausgabe:
12.57 1
3.14159Pfade: crate:: (Wurzel), self::, super:: (Elternmodul). In echten Projekten steht jedes Modul in einer eigenen Datei (mod geometrie; lädt geometrie.rs).
Cargo
Cargo ist Build-Werkzeug und Paketmanager:
cargo new mein_projekt # neues Projekt
cargo run # bauen und starten
cargo build --release # optimiert bauen
cargo check # nur prüfen (schnell)
cargo test # Tests ausführen
cargo fmt # formatieren
cargo clippy # Lint-Hinweise
cargo add serde # Abhängigkeit hinzufügen
cargo doc --open # DokumentationDie Datei Cargo.toml:
[package]
name = "mein_projekt"
version = "0.1.0"
edition = "2021"
[dependencies]
serde = { version = "1", features = ["derive"] }
rand = "0.8"Pakete heißen Crates und kommen von crates.io. Cargo.lock hält exakte Versionen fest.
Tests
Tests stehen im selben File in einem #[cfg(test)]-Modul (Unit-Tests) oder in tests/ (Integrationstests):
fn addiere(a: i32, b: i32) -> i32 { a + b }
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn addition() {
assert_eq!(addiere(2, 3), 5);
}
#[test]
#[should_panic(expected = "Division")]
fn panik() {
panic!("Division durch null");
}
#[test]
fn mit_result() -> Result<(), String> {
if addiere(1, 1) == 2 { Ok(()) } else { Err("falsch".into()) }
}
}cargo test führt alle aus. Nützliche Makros: assert!, assert_eq!, assert_ne!. Dokumentationskommentare (///) können Beispielcode enthalten, der ebenfalls als Test läuft.
Fehlerbehandlung im Projekt
Für Anwendungen nutzt man oft die Crates anyhow (einfach) und thiserror (eigene Fehlertypen):
use anyhow::{Context, Result};
fn lade(pfad: &str) -> Result<String> {
std::fs::read_to_string(pfad).with_context(|| format!("konnte {pfad} nicht lesen"))
}Nützliche Crates
| Crate | Zweck |
|---|---|
serde, serde_json | (De-)Serialisierung |
tokio | asynchrone Programmierung |
reqwest | HTTP-Client |
clap | Kommandozeilenargumente |
axum, actix-web | Webserver |
rand | Zufall |
regex | Reguläre Ausdrücke |
chrono | Datum und Zeit |
Merke
modgliedert Code,pubmacht öffentlich,useimportiertcargo new/run/build/test/fmt/clippysind die wichtigsten BefehleCargo.tomllistet Abhängigkeiten (Crates von crates.io)- Tests:
#[test]undcargo test, Makrosassert_eq!usw. anyhow/thiserrorfür Fehler,serde/tokiofür den Alltag
Übungsaufgabe
Lege mit cargo new ein Projekt an, schreibe eine Funktion mit zwei Tests und führe cargo test aus.
Quiz zur Selbstkontrolle
Was ist standardmäßig die Sichtbarkeit in Rust-Modulen?
- Privat (richtig)
- Öffentlich
- Geschützt
- Paketweit
Wie führst du Tests aus?
- cargo test (richtig)
- cargo check
- cargo run —test
- rustc —verify
Wo stehen Abhängigkeiten eines Projekts?
- In Cargo.toml (richtig)
- In main.rs
- In package.json
- In Makefile
Weiter im Kurs
Zurück: Smart Pointer, Lifetimes und Threads
Weiter: Referenz und Spickzettel
Alle Kapitel: Rust im Überblick