Communitygithub.com

rust-patterns

Idiomatische Rust-Patterns, Ownership, Fehlerbehandlung, Traits, Nebenläufigkeit und Best Practices für die Entwicklung sicherer, performanter Anwendungen. Verwenden bei der Arbeit mit oder Überprüfung von Rust-Code, wenn Ownership, Fehlerbehandlung, Traits oder Nebenläufigkeit eine Rolle spielen.

Was ist rust-patterns?

Diese Fähigkeit (Skill) bietet eine umfassende Sammlung idiomatischer Rust-Patterns und Best Practices, die Entwicklern helfen, sichere, performante und wartbare Anwendungen zu schreiben. Sie deckt Kernkonzepte wie Ownership und Borrowing zur Vermeidung von Datenrennen zur Compile-Zeit, Fehlerbehandlung mit `Result` und dem `?`-Operator, sowie den Einsatz von `thiserror` für Bibliotheken und `anyhow` für Anwendungen ab. Darüber hinaus behandelt sie die Modellierung von Zuständen mit Enums und exhaustivem Pattern Matching, die Verwendung von Traits und Generics für nullkostspielige Abstraktion und sichere Nebenläufigkeit mit `Arc<Mutex<T>>`, Channels und Async/Await. Der Skill unterstützt Entwickler auf allen gängigen Plattformen (CLI-Tools, IDE-Plugins, etc.) und ist ideal zum Schreiben, Überprüfen und Refactoring von Rust-Code, da er klare, prägnante Code-Beispiele und Anti-Patterns liefert, die direkt umgesetzt werden können.

Funktioniert mit~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/affaan-m/everything-claude-code/tree/main/skills/rust-patterns

In Ihrer bevorzugten KI fragen

Öffnet einen neuen Chat, in dem dieser Agent-Skill bereits geladen ist.

Dokumentation

Rust-Entwicklungsmuster (Patterns)

Idiomatische Rust-Patterns und Best Practices für die Entwicklung sicherer, performanter und wartbarer Anwendungen.

Wann verwenden

  • Schreiben von neuem Rust-Code
  • Überprüfen von Rust-Code
  • Refactoring von bestehendem Rust-Code
  • Entwurf von Crate-Struktur und Modul-Layout

Funktionsweise

Dieser Skill erzwingt idiomatische Rust-Konventionen in sechs Schlüsselbereichen: Ownership und Borrowing zur Vermeidung von Datenrennen zur Compile-Zeit, Result/?-Fehlerweitergabe mit thiserror für Bibliotheken und anyhow für Anwendungen, Enums und exhaustives Pattern Matching, um ungültige Zustände nicht darstellbar zu machen, Traits und Generics für nullkostspielige Abstraktion, sichere Nebenläufigkeit über Arc<Mutex<T>>, Channels und Async/Await sowie minimale pub-Oberflächen, die nach Domänen organisiert sind.

Kernprinzipien

1. Ownership und Borrowing

Rusts Ownership-System verhindert Datenrennen und Speicherfehler zur Compile-Zeit.

// Gut: Referenzen übergeben, wenn kein Ownership nötig
fn process(data: &[u8]) -> usize {
    data.len()
}

// Gut: Ownership nur übernehmen, wenn gespeichert oder verbraucht werden soll
fn store(data: Vec<u8>) -> Record {
    Record { payload: data }
}

// Schlecht: Unnötiges Klonen, um den Borrow-Checker zu umgehen
fn process_bad(data: &Vec<u8>) -> usize {
    let cloned = data.clone(); // Verschwenderisch — einfach borrowen
    cloned.len()
}

Cow für flexibles Ownership

use std::borrow::Cow;

fn normalize(input: &str) -> Cow<'_, str> {
    if input.contains(' ') {
        Cow::Owned(input.replace(' ', "_"))
    } else {
        Cow::Borrowed(input) // Nullkosten, wenn keine Mutation nötig
    }
}

Fehlerbehandlung

Result und ? verwenden — niemals unwrap() in Produktion

// Gut: Fehler mit Kontext propagieren
use anyhow::{Context, Result};

fn load_config(path: &str) -> Result<Config> {
    let content = std::fs::read_to_string(path)
        .with_context(|| format!("Fehler beim Lesen der Konfiguration von {path}"))?;
    let config: Config = toml::from_str(&content)
        .with_context(|| format!("Fehler beim Parsen der Konfiguration von {path}"))?;
    Ok(config)
}

// Schlecht: Panic bei Fehler
fn load_config_bad(path: &str) -> Config {
    let content = std::fs::read_to_string(path).unwrap(); // Panic!
    toml::from_str(&content).unwrap()
}

Bibliotheksfehler mit thiserror, Anwendungsfehler mit anyhow

// Bibliothekscode: Strukturierte, typisierte Fehler
use thiserror::Error;

#[derive(Debug, Error)]
pub enum StorageError {
    #[error("Datensatz nicht gefunden: {id}")]
    NotFound { id: String },
    #[error("Verbindung fehlgeschlagen")]
    Connection(#[from] std::io::Error),
    #[error("Ungültige Daten: {0}")]
    InvalidData(String),
}

// Anwendungscode: Flexible Fehlerbehandlung
use anyhow::{bail, Result};

fn run() -> Result<()> {
    let config = load_config("app.toml")?;
    if config.workers == 0 {
        bail!("Worker-Anzahl muss > 0 sein");
    }
    Ok(())
}

Option-Kombinatoren statt verschachteltem Matching

// Gut: Kombinatorkette
fn find_user_email(users: &[User], id: u64) -> Option<String> {
    users.iter()
        .find(|u| u.id == id)
        .map(|u| u.email.clone())
}

// Schlecht: Tief verschachteltes Matching
fn find_user_email_bad(users: &[User], id: u64) -> Option<String> {
    match users.iter().find(|u| u.id == id) {
        Some(user) => match &user.email {
            email => Some(email.clone()),
        },
        None => None,
    }
}

Enums und Pattern Matching

Zustände als Enums modellieren

// Gut: Unmögliche Zustände sind nicht darstellbar
enum ConnectionState {
    Disconnected,
    Connecting { attempt: u32 },
    Connected { session_id: String },
    Failed { reason: String, retries: u32 },
}

fn handle(state: &ConnectionState) {
    match state {
        ConnectionState::Disconnected => connect(),
        ConnectionState::Connecting { attempt } if *attempt > 3 => abort(),
        ConnectionState::Connecting { .. } => wait(),
        ConnectionState::Connected { session_id } => use_session(session_id),
        ConnectionState::Failed { retries, .. } if *retries < 5 => retry(),
        ConnectionState::Failed { reason, .. } => log_failure(reason),
    }
}

Exhaustives Matching — kein Catch-All für Geschäftslogik

// Gut: Jede Variante explizit behandeln
match command {
    Command::Start => start_service(),
    Command::Stop => stop_service(),
    Command::Restart => restart_service(),
    // Hinzufügen einer neuen Variante erzwingt Behandlung hier
}

// Schlecht: Wildcard versteckt neue Varianten
match command {
    Command::Start => start_service(),
    _ => {} // Ignoriert stillschweigend Stop, Restart und zukünftige Varianten
}

Traits und Generics

Generics akzeptieren, konkrete Typen zurückgeben

// Gut: Generische Eingabe, konkrete Ausgabe
fn read_all(reader: &mut impl Read) -> std::io::Result<Vec<u8>> {
    let mut buf = Vec::new();
    reader.read_to_end(&mut buf)?;
    Ok(buf)
}

// Gut: Trait-Bounds für mehrere Einschränkungen
fn process<T: Display + Send + 'static>(item: T) -> String {
    format!("verarbeitet: {item}")
}

Trait-Objekte für dynamischen Dispatch

// Verwenden, wenn heterogene Sammlungen oder Plugin-Systeme nötig sind
trait Handler: Send + Sync {
    fn handle(&self, request: &Request) -> Response;
}

struct Router {
    handlers: Vec<Box<dyn Handler>>,
}

// Generics verwenden, wenn Performance benötigt wird (Monomorphisierung)
fn fast_process<H: Handler>(handler: &H, request: &Request) -> Response {
    handler.handle(request)
}

Newtype-Pattern für Typsicherheit

// Gut: Unterschiedliche Typen verhindern Vertauschen von Argumenten
struct UserId(u64);
struct OrderId(u64);

fn get_order(user: UserId, order: OrderId) -> Result<Order> {
    // Kann User- und Order-IDs nicht versehentlich vertauschen
    todo!()
}

// Schlecht: Leicht, Argumente zu vertauschen
fn get_order_bad(user_id: u64, order_id: u64) -> Result<Order> {
    todo!()
}

Structs und Datenmodellierung

Builder-Pattern für komplexe Konstruktion

struct ServerConfig {
    host: String,
    port: u16,
    max_connections: usize,
}

impl ServerConfig {
    fn builder(host: impl Into<String>, port: u16) -> ServerConfigBuilder {
        ServerConfigBuilder { host: host.into(), port, max_connections: 100 }
    }
}

struct ServerConfigBuilder { host: String, port: u16, max_connections: usize }

impl ServerConfigBuilder {
    fn max_connections(mut self, n: usize) -> Self { self.max_connections = n; self }
    fn build(self) -> ServerConfig {
        ServerConfig { host: self.host, port: self.port, max_connections: self.max_connections }
    }
}

// Verwendung: ServerConfig::builder("localhost", 8080).max_connections(200).build()

Iteratoren und Closures

Iterator-Ketten bevorzugen statt manueller Schleifen

// Gut: Deklarativ, lazy, zusammensetzbar
let active_emails: Vec<String> = users.iter()
    .filter(|u| u.is_active)
    .map(|u| u.email.clone())
    .collect();

// Schlecht: Imperative Akkumulation
let mut active_emails = Vec::new();
for user in &users {
    if user.is_active {
        active_emails.push(user.email.clone());
    }
}

collect() mit Typannotation verwenden

// In verschiedene Typen sammeln
let names: Vec<_> = items.iter().map(|i| &i.name).collect();
let lookup: HashMap<_, _> = items.iter().map(|i| (i.id, i)).collect();
let combined: String = parts.iter().copied().collect();

// Results sammeln — bricht beim ersten Fehler ab
let parsed: Result<Vec<i32>, _> = strings.iter().map(|s| s.parse()).collect();

Nebenläufigkeit

Arc<Mutex<T>> für gemeinsam genutzten, veränderlichen Zustand

use std::sync::{Arc, Mutex};

let counter = Arc::new(Mutex::new(0));
let handles: Vec<_> = (0..10).map(|_| {
    let counter = Arc::clone(&counter);
    std::thread::spawn(move || {
        let mut num = counter.lock().expect("Mutex vergiftet");
        *num += 1;
    })
}).collect();

for handle in handles {
    handle.join().expect("Worker-Thread ist in Panik ausgegangen");
}

Channels für Nachrichtenaustausch

use std::sync::mpsc;

let (tx, rx) = mpsc::sync_channel(16); // Bounded Channel mit Backpressure

for i in 0..5 {
    let tx = tx.clone();
    std::thread::spawn(move || {
        tx.send(format!("Nachricht {i}")).expect("Empfänger getrennt");
    });
}
drop(tx); // Sender schließen, damit rx-Iterator terminiert

for msg in rx {
    println!("{msg}");
}

Async mit Tokio

use tokio::time::Duration;

async fn fetch_with_timeout(url: &str) -> Result<String> {
    let response = tokio::time::timeout(
        Duration::from_secs(5),
        reqwest::get(url),
    )
    .await
    .context("Anfrage zeitlich ausgelaufen")?
    .context("Anfrage fehlgeschlagen")?;

    response.text().await.context("Fehler beim Lesen des Rumpfs")
}

// Nebenläufige Aufgaben starten
async fn fetch_all(urls: Vec<String>) -> Vec<Result<String>> {
    let handles: Vec<_> = urls.into_iter()
        .map(|url| tokio::spawn(async move {
            fetch_with_timeout(&url).await
        }))
        .collect();

    let mut results = Vec::with_capacity(handles.len());
    for handle in handles {
        results.push(handle.await.unwrap_or_else(|e| panic!("Gestartete Aufgabe in Panik ausgegangen: {e}")));
    }
    results
}

Unsicherer Code (Unsafe)

Wann Unsafe akzeptabel ist

// Akzeptabel: FFI-Grenze mit dokumentierten Invarianten (Rust 2024+)
/// # Sicherheit
/// `ptr` muss ein gültiger, ausgerichteter Zeiger auf einen initialisierten `Widget` sein.
unsafe fn widget_from_raw<'a>(ptr: *const Widget) -> &'a Widget {
    // SICHERHEIT: Aufrufer garantiert, dass ptr gültig und ausgerichtet ist
    unsafe { &*ptr }
}

// Akzeptabel: Performance-kritischer Pfad mit Korrektheitsbeweis
// SICHERHEIT: index ist aufgrund der Schleifengrenze immer < len
unsafe { slice.get_unchecked(index) }

Wann Unsafe NICHT akzeptabel ist

// Schlecht: Unsafe zur Umgehung des Borrow-Checkers verwenden
// Schlecht: Unsafe aus Bequemlichkeit verwenden
// Schlecht: Unsafe ohne Safety-Kommentar verwenden
// Schlecht: Zwischen nicht verwandten Typen transmutieren

Modulsystem und Crate-Struktur

Nach Domäne organisieren, nicht nach Typ

my_app/
├── src/
│   ├── main.rs
│   ├── lib.rs
│   ├── auth/          # Domänenmodul
│   │   ├── mod.rs
│   │   ├── token.rs
│   │   └── middleware.rs
│   ├── orders/        # Domänenmodul
│   │   ├── mod.rs
│   │   ├── model.rs
│   │   └── service.rs
│   └── db/            # Infrastruktur
│       ├── mod.rs
│       └── pool.rs
├── tests/             # Integrationstests
├── benches/           # Benchmarks
└── Cargo.toml

Sichtbarkeit — Minimal exponieren

// Gut: pub(crate) für internes Teilen
pub(crate) fn validate_input(input: &str) -> bool {
    !input.is_empty()
}

// Gut: Öffentliche API aus lib.rs re-exportieren
pub mod auth;
pub use auth::AuthMiddleware;

// Schlecht: Alles pub machen
pub fn internal_helper() {} // Sollte pub(crate) oder privat sein

Tooling-Integration

Wesentliche Befehle

# Bauen und Prüfen
cargo build
cargo check              # Schnelle Typprüfung ohne Codegenerierung
cargo clippy             # Lints und Vorschläge
cargo fmt                # Code formatieren

# Testen
cargo test
cargo test -- --nocapture    # println-Ausgabe anzeigen
cargo test --lib             # Nur Unit-Tests
cargo test --test integration # Nur Integrationstests

# Abhängigkeiten
cargo audit              # Sicherheitsaudit
cargo tree               # Abhängigkeitsbaum
cargo update             # Abhängigkeiten aktualisieren

# Performance
cargo bench              # Benchmarks ausführen

Kurzreferenz: Rust-Idiome

IdiomBeschreibung
Borrowen, nicht klonen&T übergeben statt zu klonen, es sei denn, Ownership wird benötigt
Ungültige Zustände nicht darstellbar machenEnums verwenden, um nur gültige Zustände zu modellieren
? statt unwrap()Fehler propagieren, niemals in Bibliotheks-/Produktionscode panicken
Parsen, nicht validierenUnstrukturierte Daten an der Grenze in typisierte Strukturen umwandeln
Newtype für TypsicherheitPrimitive in Newtypes wrappen, um Argumentvertauschungen zu verhindern
Iteratoren gegenüber Schleifen bevorzugenDeklarative Ketten sind klarer und oft schneller
#[must_use] auf ResultsSicherstellen, dass Aufrufer Rückgabewerte behandeln
Cow für flexibles OwnershipAllokationen vermeiden, wenn Borrowing ausreicht
Exhaustives MatchingKein Wildcard _ für geschäftskritische Enums
Minimale pub-Oberflächepub(crate) für interne APIs verwenden

Anti-Patterns, die vermieden werden sollten

// Schlecht: .unwrap() in Produktionscode
let value = map.get("key").unwrap();

// Schlecht: .clone(), um den Borrow-Checker zufriedenzustellen, ohne zu verstehen, warum
let data = expensive_data.clone();
process(&original, &data);

// Schlecht: String verwenden, wenn &str ausreicht
fn greet(name: String) { /* sollte &str sein */ }

// Schlecht: Box<dyn Error> in Bibliotheken (stattdessen thiserror verwenden)
fn parse(input: &str) -> Result<Data, Box<dyn std::error::Error>> { todo!() }

// Schlecht: must_use-Warnungen ignorieren
let _ = validate(input); // Ein Result stillschweigend verwerfen

// Schlecht: Blockieren im async-Kontext
async fn bad_async() {
    std::thread::sleep(Duration::from_secs(1)); // Blockiert den Executor!
    // Verwenden: tokio::time::sleep(Duration::from_secs(1)).await;
}

Denken Sie daran: Wenn es kompiliert, ist es wahrscheinlich korrekt — aber nur, wenn Sie unwrap() vermeiden, unsafe minimieren und das Typsystem für sich arbeiten lassen.

Individual skills in this repo

This repo contains 20 individual skills — each has its own dedicated page.

accessibility

Design, implement, and audit inclusive digital products using WCAG 2.2 Level AA. Use when building or auditing UI that must meet WCAG 2.2 Level AA, or when reviewing a change for keyboard, contrast, or screen-reader support.

affaan-m/claude-api

Anthropic Claude API patterns for Python and TypeScript. Covers Messages API, streaming, tool use, vision, extended thinking, batches, prompt caching, and Claude Agent SDK. Use when building applications with the Claude API or Anthropic SDKs.

affaan-m/everything-claude-code

End-to-end marketing campaign planning and execution. Covers audience research, positioning, campaign angle definition, landing page copy, email sequences, social posts, ad copy, short-form video scripts, and content calendars. Use as the orchestration layer for multi-channel product launches. Use when planning or executing a multi-channel product launch, or producing landing page, email, social, or ad copy.

affaan-m/everything-claude-code

Development conventions and patterns for everything-claude-code. JavaScript project with conventional commits.

affaan-m/everything-claude-code-conventions

Development conventions and patterns for everything-claude-code. JavaScript project with conventional commits.

affaan-m/frontend-design

Create distinctive, production-grade frontend interfaces with high design quality. Use when the user asks to build web components, pages, or applications and the visual direction matters as much as the code quality.

affaan-m/gget

gget CLI and Python workflow for quick genomic database queries, sequence lookup, BLAST-style searches, enrichment checks, and reproducible bioinformatics evidence logs.

affaan-m/literature-review

Systematic literature-review workflow for academic, biomedical, technical, and scientific topics, including search planning, source screening, synthesis, citation checks, and evidence logging.

affaan-m/motion-ui

Production-ready UI motion system for React/Next.js. Use when implementing animations, transitions, or motion patterns.

affaan-m/project-guidelines-example

Example project-specific skill template based on a real production application.

affaan-m/pubmed-database

Direct PubMed and NCBI E-utilities search workflows for biomedical literature, MeSH queries, PMID lookup, citation retrieval, and API-backed literature monitoring.

affaan-m/scholar-evaluation

Structured scholarly-work evaluation for papers, proposals, literature reviews, methods sections, evidence quality, citation support, and research-writing feedback.

affaan-m/uspto-database

USPTO patent and trademark data workflow for official record lookup, PatentSearch queries, TSDR checks, assignment data, and reproducible IP research logs.

agent-architecture-audit

Full-stack diagnostic for agent and LLM applications. Audits the 12-layer agent stack for wrapper regression, memory pollution, tool discipline failures, hidden repair loops, and rendering corruption. Produces severity-ranked findings with code-first fixes. Essential for developers building agent applications, autonomous loops, or any LLM-powered feature. Use when an agent or LLM feature misbehaves and the failing layer is unknown, or before shipping an agent stack.

agent-eval

Head-to-head comparison of coding agents (Claude Code, Aider, Codex, etc.) on custom tasks with pass rate, cost, time, and consistency metrics. Use when choosing between coding agents, or when a change to an agent setup needs measured pass rate, cost, and time rather than an impression.

agent-harness-construction

Design and optimize AI agent action spaces, tool definitions, and observation formatting for higher completion rates. Use when defining or revising an agent

agentic-engineering

Operate as an agentic engineer using eval-first execution, decomposition, and cost-aware model routing. Use when planning or executing engineering work that agents will carry out end to end.

agentic-os

Build persistent multi-agent operating systems on Claude Code. Covers kernel architecture, specialist agents, slash commands, file-based memory, scheduled automation, and state management without external databases. Use when building a persistent multi-agent system on Claude Code with its own memory, commands, and scheduling.

agent-introspection-debugging

Structured self-debugging workflow for AI agent failures using capture, diagnosis, contained recovery, and introspection reports. Use when an agent run fails and you need a reproducible diagnosis instead of a retry.

agent-payment-x402

Add x402 payment execution to AI agents with per-task budgets, spending controls, and non-custodial wallets. Supports Base through agentwallet-sdk and X Layer through OKX Payments / OKX Agent Payments Protocol. Use when an agent must pay for something itself and needs per-task budgets, spending controls, and a non-custodial wallet.

Verwandte Skills