Rust-Coding
Workflow
-
Orientieren. Lies die Quellen der Wahrheit des Projekts, bevor du schreibst:
rust-toolchain.toml,Cargo.toml(edition,rust-version,[lints],[workspace]),clippy.toml,rustfmt.toml,.cargo/config.tomlsowie die CI-Konfiguration,justfile,Makefileoderxtaskfür die kanonischen Check-Befehle. Lies das Modul, das du änderst, und seine Nachbarn; verwende deren Helfer, Fehlertypen und Muster wieder.
Erledigt, wenn: du die Edition, das MSRV, die Lint-Policy, jeden Eintrag indisallowed-methods/disallowed-typesund die Check-Befehle des Projekts nennen kannst. -
Modelliere die Typen. Entwerfe Daten vor dem Kontrollfluss, gemäß Typen. Änderst du die öffentliche API einer Bibliothek: lies
references/api.md.
Erledigt, wenn: jede Invariante, auf die sich die Änderung stützt, in einem Typ codiert ist oder von einemexpectgehalten wird, dessen Nachricht die Invariante benennt. -
Implementiere in einer engen Schleife. Arbeite in kleinen Schritten und führe nach jedem
cargo checkaus. Lies die gesamte Diagnose: Ihrehelp:-Zeile nennt in der Regel die Lösung, undrustc --explain E0502erweitert einen Fehlercode. Für die API einer Abhängigkeit lies deren Quelle in der gesperrten Version (Cargo.lock) unter$CARGO_HOME/registry/src/. Massenumbenennungen erfolgen über rust-analyzer umbenennen oderast-grep;cargo clippy --fixwendet maschinell anwendbare Vorschläge an. Fehlerbehebung: schreibe zuerst den Regressionstest und beobachte, wie er rot wird.
Erledigt, wenn: die Änderung ohne Warnungen auf den von dir geänderten Zeilen kompiliert und jeder Regressionstest vor der Behebung rot und danach grün wurde. -
Verifiziere. Führe die Check-Befehle des Projekts aus Schritt 1 aus; andernfalls:
cargo fmt --all cargo clippy --workspace --all-targets --all-features -- -D warnings cargo test --workspace --all-features- Projekt ohne
[lints]-Policy: führe auchcargo clippy --all-targets -- -W clippy::pedanticaus und behebe Treffer auf von dir geänderten Zeilen. - Sich gegenseitig ausschließende Features: ersetze
--all-featuresdurch jede von CI getestete Feature-Kombination. cargo nextestüberspringt Doc-Tests: fügecargo test --dochinzu.- Öffentliche Docs geändert:
RUSTDOCFLAGS="-D warnings" cargo doc --no-deps --all-features. unsafeberührt: liesreferences/unsafe.md.- Behebe Lints an der Ursache. Wenn eine Unterdrückung richtig ist, begrenze
#[expect(clippy::lint_name, reason = "...")]auf das kleinste Element. Erledigt, wenn: jeder Befehl mit 0 beendet wird, von dir geänderte Zeilen keine Warnungen auslösen und jede neue Unterdrückung einenreasonträgt.
- Projekt ohne
-
Überprüfe den Diff selbst. Lies den vollständigen
git differneut, nicht aus dem Gedächtnis, und prüfe ihn gegen Regeln sowie die Regeln jeder Referenzdatei, deren Zweig der Diff berührt.
Erledigt, wenn: jeder Hunk für die Aufgabe erforderlich ist, Prototyp-Code unddbg!/todo!entfernt wurden, Doc-Kommentare dem Verhalten entsprechen und jede anwendbare Regel für jeden Hunk gilt.
Fremden Code überprüfen: führe Schritt 1 aus, führe die Befehle aus Schritt 4 aus, wenn möglich, und wende dann Schritt 5 auf deren Diff an. Melde jeden Befund als Pfad:Zeile, die Regel und die Lösung.
Regeln
Ownership
- Ausleihen in Parametern:
&str,&[T],&Path,&T. NimmString,Vec<T>oderTnur dann by Value, wenn die Funktion sie speichert oder konsumiert. - Jeder
.clone()verdient seinen Platz: der Aufgerufene benötigt Ownership, oder der Wert ist ein günstiger Handle (Arc::clone(&handle)). - Wenn der Borrow-Checker Einwände hat, strukturiere zuerst um: verkürze die Ausleihe, leihe disjunkte Felder separat aus,
std::mem::take/replace, Indizes in einVec. Geteilte veränderliche Ownership (Rc<RefCell<_>>,Arc<Mutex<_>>) ist der letzte Ausweg. - Gib
impl Iterator<Item = T>zurück, wenn der Aufrufer nur iteriert.
Typen
- Mache illegale Zustände nicht darstellbar: ein
enummit zustandsabhängigen Daten, stattbool-Flags plusOption-Felder; Newtypes für IDs, Einheiten und validierte Werte (struct Port(NonZeroU16)). - Parse, nicht validieren: konvertiere nicht vertrauenswürdige Eingaben einmal an der Grenze (
TryFrom,FromStr,#[serde(try_from = "Raw")]) und gib den geparsten Typ nach innen weiter. - Matche exhaustiv auf enums, die du besitzt. Ein
_-Arm ist nur dann richtig, wenn eine zukünftige Variante ebenfalls diesen Zweig nehmen soll. - Konvertiere Ganzzahlen mit
From/TryFrom;askürzt ab und kehrt das Vorzeichen stillschweigend um.
Fehler und Panics
- Bibliothek: ein
thiserror-Enum pro Fehlerdomäne. Binärprogramm:anyhow::Resultmit.context(...). - Panics bedeuten Bugs.
unwrap()lebt in Tests; Produktionscode verwendet?oderexpect("..."), das die Invariante nennt, die einen Fehler unmöglich macht.
Aktuelle Idiome
Ältere Muster dominieren Trainingsdaten. Bevorzuge die aktuelle Form, wenn rust-version es erlaubt; neue Crates verwenden edition = "2024". clippy::incompatible_msrv erfasst nur neuere std-APIs; Sprach- und Cargo-Features benötigen cargo +<msrv> check.
| Bevorzuge | Statt | Seit |
|---|---|---|
std::sync::LazyLock, OnceLock | lazy_static!, once_cell | 1.80, 1.70 |
let Some(x) = opt else { return ... }; | match + früher Rückkehr | 1.65 |
if let Some(x) = a && x > 0 | verschachteltes if let | 1.88, edition 2024 |
nativ async fn in Traits | #[async_trait], weiterhin nötig für dyn Trait | 1.75 |
| `async | {}-Closures, AsyncFn`-Bounds | |
#[expect(lint, reason = "...")] | #[allow(lint)] | 1.81 |
&raw const x, &raw mut x | ptr::addr_of! | 1.82 |
opt.is_some_and(f), opt.is_none_or(f) | map_or(false, f), map_or(true, f) | 1.70, 1.82 |
std::hint::black_box | criterion::black_box | 1.66 |
[lints] in Cargo.toml für gemeinsame Policy | #![warn(...)] in jeder Crate-Wurzel | 1.74 |
cargo:: Build-Script-Direktiven | cargo: | 1.77 |
Docs und Kommentare
- Öffentliche Items erhalten
///-Docs:# Errorsbei fehlbaren Funktionen,# Panicsbei panikenden, Beispiele als Doc-Tests mit?. - Kommentare erklären das Warum; der Code zeigt das Was.
Abhängigkeiten
- Verwende wieder, was der Workspace bereits verwendet (
[workspace.dependencies],cargo tree -i <crate>), und bevorzuge std, wenn es den Bedarf abdeckt. - Füge mit
cargo addhinzu (MSRV-bewusst) und aktiviere nur die von dir verwendeten Features.
Referenzen
Lade diejenige, die zum aktuellen Branch passt:
references/api.md: Entwerfen oder Ändern der öffentlichen API einer Bibliothek, Namensgebung, Trait-Implementierungen, Semver.references/errors.md: Definieren von Fehlertypen, Propagation, Panic vs.Result.references/async.md: Async, Tokio, Threads, Channels, Locks, Atomics.references/unsafe.md:unsafe, FFI, rohe Zeiger, manuellesSend/Sync.references/cargo.md:Cargo.toml, Workspaces, Features, Profile, Build-Skripte, Crate-Auswahl.references/lints.md: Einrichten der Lint-Konfiguration für eine Crate oder einen Workspace.references/testing.md: Schreiben von Tests, Property- und Snapshot-Tests, Benchmarks.references/perf.md: Optimieren eines gemessenen Hot Paths.