Communitygithub.com

Padrões Rust

Padrões idiomáticos Rust, ownership, tratamento de erros, traits, concorrência e melhores práticas para criar aplicações seguras e de alto desempenho. Use ao escrever ou revisar código Rust onde ownership, tratamento de erros, traits ou concorrência estejam em questão.

O que é Padrões Rust?

Esta habilidade (skill) fornece um guia abrangente de padrões e melhores práticas idiomáticas Rust para construir aplicações seguras, performáticas e de fácil manutenção. Ela abrange ownership e borrowing para prevenir corridas de dados em tempo de compilação, `Result`/`?` para propagação de erros com `thiserror` (bibliotecas) e `anyhow` (aplicações), enums e pattern matching exaustivo para tornar estados inválidos irrepresentáveis, traits e genéricos para abstração de custo zero, concorrência segura via `Arc<Mutex<T>>`, canais e async/await, e superfícies `pub` mínimas organizadas por domínio. A habilidade inclui exemplos extensos de código, um guia de referência rápida e uma seção de antipadrões, sendo útil para escrever, revisar ou refatorar código Rust em qualquer contexto, seja em bibliotecas, aplicações CLI, serviços web ou sistemas de baixo nível.

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

Perguntar na sua IA favorita

Abre um novo chat com esta habilidade de agente já pré-carregada.

Documentação

Padrões de Desenvolvimento Rust

Padrões idiomáticos Rust e melhores práticas para construir aplicações seguras, performáticas e de fácil manutenção.

Quando Usar

  • Escrevendo novo código Rust
  • Revisando código Rust
  • Refatorando código Rust existente
  • Projetando estrutura de crate e layout de módulos

Como Funciona

Esta habilidade reforça convenções idiomáticas Rust em seis áreas principais: ownership e borrowing para prevenir corridas de dados em tempo de compilação, propagação de erros com Result/? usando thiserror para bibliotecas e anyhow para aplicações, enums e pattern matching exaustivo para tornar estados inválidos irrepresentáveis, traits e genéricos para abstração de custo zero, concorrência segura via Arc<Mutex<T>>, canais e async/await, e superfícies pub mínimas organizadas por domínio.

Princípios Centrais

1. Ownership e Borrowing

O sistema de ownership do Rust previne corridas de dados e bugs de memória em tempo de compilação.

// Bom: Passe referências quando não precisar de ownership
fn process(data: &[u8]) -> usize {
    data.len()
}

// Bom: Assuma ownership apenas quando precisar armazenar ou consumir
fn store(data: Vec<u8>) -> Record {
    Record { payload: data }
}

// Ruim: Clonar desnecessariamente para evitar o borrow checker
fn process_bad(data: &Vec<u8>) -> usize {
    let cloned = data.clone(); // Desperdício — apenas tome emprestado
    cloned.len()
}

Use Cow para Ownership Flexível

use std::borrow::Cow;

fn normalize(input: &str) -> Cow<'_, str> {
    if input.contains(' ') {
        Cow::Owned(input.replace(' ', "_"))
    } else {
        Cow::Borrowed(input) // Custo zero quando nenhuma mutação é necessária
    }
}

Tratamento de Erros

Use Result e ? — Nunca unwrap() em Produção

// Bom: Propague erros com contexto
use anyhow::{Context, Result};

fn load_config(path: &str) -> Result<Config> {
    let content = std::fs::read_to_string(path)
        .with_context(|| format!("falha ao ler config de {path}"))?;
    let config: Config = toml::from_str(&content)
        .with_context(|| format!("falha ao analisar config de {path}"))?;
    Ok(config)
}

// Ruim: Panico em caso de erro
fn load_config_bad(path: &str) -> Config {
    let content = std::fs::read_to_string(path).unwrap(); // Pânico!
    toml::from_str(&content).unwrap()
}

Erros de Biblioteca com thiserror, Erros de Aplicação com anyhow

// Código de biblioteca: erros estruturados e tipados
use thiserror::Error;

#[derive(Debug, Error)]
pub enum StorageError {
    #[error("registro não encontrado: {id}")]
    NotFound { id: String },
    #[error("conexão falhou")]
    Connection(#[from] std::io::Error),
    #[error("dados inválidos: {0}")]
    InvalidData(String),
}

// Código de aplicação: tratamento de erros flexível
use anyhow::{bail, Result};

fn run() -> Result<()> {
    let config = load_config("app.toml")?;
    if config.workers == 0 {
        bail!("contagem de workers deve ser > 0");
    }
    Ok(())
}

Combinadores de Option ao Invés de Match Aninhado

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

// Ruim: Match profundamente aninhado
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 e Pattern Matching

Modele Estados como Enums

// Bom: Estados impossíveis são irrepresentáveis
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),
    }
}

Matching Exaustivo — Sem Catch-All para Lógica de Negócio

// Bom: Trate cada variante explicitamente
match command {
    Command::Start => start_service(),
    Command::Stop => stop_service(),
    Command::Restart => restart_service(),
    // Adicionar uma nova variante força o tratamento aqui
}

// Ruim: Curinga esconde novas variantes
match command {
    Command::Start => start_service(),
    _ => {} // Ignora silenciosamente Stop, Restart e variantes futuras
}

Traits e Genéricos

Aceite Genéricos, Retorne Tipos Concretos

// Bom: Entrada genérica, saída concreta
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)
}

// Bom: Trait bounds para múltiplas restrições
fn process<T: Display + Send + 'static>(item: T) -> String {
    format!("processado: {item}")
}

Objetos Trait para Dispatch Dinâmico

// Use quando precisar de coleções heterogêneas ou sistemas de plugins
trait Handler: Send + Sync {
    fn handle(&self, request: &Request) -> Response;
}

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

// Use genéricos quando precisar de performance (monomorfização)
fn fast_process<H: Handler>(handler: &H, request: &Request) -> Response {
    handler.handle(request)
}

Padrão Newtype para Segurança de Tipos

// Bom: Tipos distintos previnem troca de argumentos
struct UserId(u64);
struct OrderId(u64);

fn get_order(user: UserId, order: OrderId) -> Result<Order> {
    // Não é possível trocar acidentalmente os IDs de usuário e pedido
    todo!()
}

// Ruim: Fácil trocar argumentos
fn get_order_bad(user_id: u64, order_id: u64) -> Result<Order> {
    todo!()
}

Structs e Modelagem de Dados

Padrão Builder para Construção Complexa

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 }
    }
}

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

Iteradores e Closures

Prefira Cadeias de Iteradores a Loops Manuais

// Bom: Declarativo, lazy, componível
let active_emails: Vec<String> = users.iter()
    .filter(|u| u.is_active)
    .map(|u| u.email.clone())
    .collect();

// Ruim: Acumulação imperativa
let mut active_emails = Vec::new();
for user in &users {
    if user.is_active {
        active_emails.push(user.email.clone());
    }
}

Use collect() com Anotação de Tipo

// Colete em diferentes tipos
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();

// Colete Results — curto-circuito no primeiro erro
let parsed: Result<Vec<i32>, _> = strings.iter().map(|s| s.parse()).collect();

Concorrência

Arc<Mutex<T>> para Estado Mutável Compartilhado

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 envenenado");
        *num += 1;
    })
}).collect();

for handle in handles {
    handle.join().expect("thread worker entrou em pânico");
}

Canais para Passagem de Mensagens

use std::sync::mpsc;

let (tx, rx) = mpsc::sync_channel(16); // Canal limitado com backpressure

for i in 0..5 {
    let tx = tx.clone();
    std::thread::spawn(move || {
        tx.send(format!("mensagem {i}")).expect("receiver desconectado");
    });
}
drop(tx); // Feche o sender para que o iterador rx termine

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

Async com 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("requisição excedeu tempo limite")?
    .context("requisição falhou")?;

    response.text().await.context("falha ao ler corpo")
}

// Dispare tarefas concorrentes
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!("tarefa disparada entrou em pânico: {e}")));
    }
    results
}

Código Inseguro (Unsafe)

Quando Unsafe é Aceitável

// Aceitável: Limite FFI com invariantes documentados (Rust 2024+)
/// # Segurança
/// `ptr` deve ser um ponteiro válido e alinhado para um `Widget` inicializado.
unsafe fn widget_from_raw<'a>(ptr: *const Widget) -> &'a Widget {
    // SEGURANÇA: o chamador garante que ptr é válido e alinhado
    unsafe { &*ptr }
}

// Aceitável: Caminho crítico de performance com prova de correção
// SEGURANÇA: index é sempre < len devido ao limite do loop
unsafe { slice.get_unchecked(index) }

Quando Unsafe NÃO é Aceitável

// Ruim: Usar unsafe para burlar o borrow checker
// Ruim: Usar unsafe por conveniência
// Ruim: Usar unsafe sem um comentário de Segurança
// Ruim: Transmutar entre tipos não relacionados

Sistema de Módulos e Estrutura de Crate

Organize por Domínio, Não por Tipo

my_app/
├── src/
│   ├── main.rs
│   ├── lib.rs
│   ├── auth/          # Módulo de domínio
│   │   ├── mod.rs
│   │   ├── token.rs
│   │   └── middleware.rs
│   ├── orders/        # Módulo de domínio
│   │   ├── mod.rs
│   │   ├── model.rs
│   │   └── service.rs
│   └── db/            # Infraestrutura
│       ├── mod.rs
│       └── pool.rs
├── tests/             # Testes de integração
├── benches/           # Benchmarks
└── Cargo.toml

Visibilidade — Exponha Minimamente

// Bom: pub(crate) para compartilhamento interno
pub(crate) fn validate_input(input: &str) -> bool {
    !input.is_empty()
}

// Bom: Re-exporte a API pública de lib.rs
pub mod auth;
pub use auth::AuthMiddleware;

// Ruim: Tornando tudo pub
pub fn internal_helper() {} // Deveria ser pub(crate) ou privado

Integração com Ferramentas

Comandos Essenciais

# Compilar e verificar
cargo build
cargo check              # Verificação de tipo rápida sem geração de código
cargo clippy             # Lints e sugestões
cargo fmt                # Formatador de código

# Testes
cargo test
cargo test -- --nocapture    # Mostrar saída println
cargo test --lib             # Apenas testes unitários
cargo test --test integration # Apenas testes de integração

# Dependências
cargo audit              # Auditoria de segurança
cargo tree               # Árvore de dependências
cargo update             # Atualizar dependências

# Performance
cargo bench              # Executar benchmarks

Referência Rápida: Expressões Idiomáticas Rust

ExpressãoDescrição
Empreste, não clonePasse &T em vez de clonar, a menos que ownership seja necessário
Torne estados ilegais irrepresentáveisUse enums para modelar apenas estados válidos
? em vez de unwrap()Propague erros, nunca entre em pânico em bibliotecas/código de produção
Analise, não valideConverta dados não estruturados em structs tipados na fronteira
Newtype para segurança de tiposEmpacote primitivos em newtypes para evitar troca de argumentos
Prefira iteradores a loopsCadeias declarativas são mais claras e frequentemente mais rápidas
#[must_use] em ResultsGaranta que chamadores tratem valores de retorno
Cow para ownership flexívelEvite alocações quando o empréstimo for suficiente
Matching exaustivoSem curinga _ para enums críticos ao negócio
Superfície pub mínimaUse pub(crate) para APIs internas

Antipadrões a Evitar

// Ruim: .unwrap() em código de produção
let value = map.get("key").unwrap();

// Ruim: .clone() para satisfazer o borrow checker sem entender o porquê
let data = expensive_data.clone();
process(&original, &data);

// Ruim: Usar String quando &str é suficiente
fn greet(name: String) { /* deveria ser &str */ }

// Ruim: Box<dyn Error> em bibliotecas (use thiserror em vez disso)
fn parse(input: &str) -> Result<Data, Box<dyn std::error::Error>> { todo!() }

// Ruim: Ignorar avisos de must_use
let _ = validate(input); // Descartando silenciosamente um Result

// Ruim: Bloqueio em contexto async
async fn bad_async() {
    std::thread::sleep(Duration::from_secs(1)); // Bloqueia o executor!
    // Use: tokio::time::sleep(Duration::from_secs(1)).await;
}

Lembre-se: Se compila, provavelmente está correto — mas apenas se você evitar unwrap(), minimizar unsafe e deixar o sistema de tipos trabalhar a seu favor.

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.

Habilidades Relacionadas