Communitygithub.com

rust-patterns

Patrones idiomáticos de Rust, ownership, manejo de errores, traits, concurrencia y mejores prácticas para construir aplicaciones seguras y eficientes. Úsalo al escribir o revisar código Rust y cuando estén en cuestión ownership, manejo de errores, traits o concurrencia.

¿Qué es rust-patterns?

Este skill proporciona una guía completa de patrones idiomáticos y mejores prácticas de Rust para construir aplicaciones seguras, eficientes y mantenibles. Abarca seis áreas clave: ownership y borrowing para prevenir condiciones de carrera en tiempo de compilación, propagación de errores con `Result` y `?` usando `thiserror` para librerías y `anyhow` para aplicaciones, enums y pattern matching exhaustivo para hacer que los estados ilegales sean irrepresentables, traits y genéricos para abstracción de costo cero, concurrencia segura mediante `Arc<Mutex<T>>`, canales y async/await, y superficies `pub` mínimas organizadas por dominio. Está diseñado para cualquier agente de IA que escriba o revise código Rust (Claude Code, Cursor, Codex, etc.) y contiene ejemplos de código, tablas de referencia rápida, y anti-patrones a evitar, junto con integración de herramientas como `cargo clippy` y `cargo audit`.

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

Preguntar en tu IA favorita

Abre un nuevo chat con esta habilidad de agente ya precargada.

Documentación

Patrones de Desarrollo en Rust

Patrones idiomáticos de Rust y mejores prácticas para construir aplicaciones seguras, eficientes y mantenibles.

Cuándo Usarlo

  • Escribiendo nuevo código Rust
  • Revisando código Rust
  • Refactorizando código Rust existente
  • Diseñando estructura de crate y organización de módulos

Cómo Funciona

Este skill aplica convenciones idiomáticas de Rust en seis áreas clave: ownership y borrowing para prevenir condiciones de carrera en tiempo de compilación, propagación de errores con Result/? usando thiserror para librerías y anyhow para aplicaciones, enums y pattern matching exhaustivo para hacer que los estados ilegales sean irrepresentables, traits y genéricos para abstracción de costo cero, concurrencia segura mediante Arc<Mutex<T>>, canales y async/await, y superficies pub mínimas organizadas por dominio.

Principios Fundamentales

1. Ownership y Borrowing

El sistema de ownership de Rust previene condiciones de carrera y errores de memoria en tiempo de compilación.

// Bien: Pasa referencias cuando no necesitas ownership
fn process(data: &[u8]) -> usize {
    data.len()
}

// Bien: Toma ownership solo cuando necesitas almacenar o consumir
fn store(data: Vec<u8>) -> Record {
    Record { payload: data }
}

// Mal: Clonar innecesariamente para evitar el borrow checker
fn process_bad(data: &Vec<u8>) -> usize {
    let cloned = data.clone(); // Desperdicio — solo presta
    cloned.len()
}

Usa Cow para Ownership Flexible

use std::borrow::Cow;

fn normalize(input: &str) -> Cow<'_, str> {
    if input.contains(' ') {
        Cow::Owned(input.replace(' ', "_"))
    } else {
        Cow::Borrowed(input) // Costo cero cuando no se necesita mutación
    }
}

Manejo de Errores

Usa Result y ? — Nunca unwrap() en Producción

// Bien: Propaga errores con contexto
use anyhow::{Context, Result};

fn load_config(path: &str) -> Result<Config> {
    let content = std::fs::read_to_string(path)
        .with_context(|| format!("fallo al leer configuración desde {path}"))?;
    let config: Config = toml::from_str(&content)
        .with_context(|| format!("fallo al parsear configuración desde {path}"))?;
    Ok(config)
}

// Mal: Panics en caso de error
fn load_config_bad(path: &str) -> Config {
    let content = std::fs::read_to_string(path).unwrap(); // ¡Panic!
    toml::from_str(&content).unwrap()
}

Errores de Librería con thiserror, Errores de Aplicación con anyhow

// Código de librería: errores estructurados y tipados
use thiserror::Error;

#[derive(Debug, Error)]
pub enum StorageError {
    #[error("registro no encontrado: {id}")]
    NotFound { id: String },
    #[error("fallo de conexión")]
    Connection(#[from] std::io::Error),
    #[error("datos inválidos: {0}")]
    InvalidData(String),
}

// Código de aplicación: manejo flexible de errores
use anyhow::{bail, Result};

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

Combinadores de Option en Lugar de Matching Anidado

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

// Mal: Matching profundamente anidado
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 y Pattern Matching

Modela Estados como Enums

// Bien: Estados imposibles son irrepresentables
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 Exhaustivo — Sin Comodín para Lógica de Negocio

// Bien: Maneja cada variante explícitamente
match command {
    Command::Start => start_service(),
    Command::Stop => stop_service(),
    Command::Restart => restart_service(),
    // Añadir una nueva variante fuerza a manejarla aquí
}

// Mal: El comodín oculta nuevas variantes
match command {
    Command::Start => start_service(),
    _ => {} // Ignora silenciosamente Stop, Restart y variantes futuras
}

Traits y Genéricos

Acepta Genéricos, Retorna Tipos Concretos

// Bien: Entrada genérica, salida 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)
}

// Bien: Límites de trait para múltiples restricciones
fn process<T: Display + Send + 'static>(item: T) -> String {
    format!("procesado: {item}")
}

Objetos Trait para Despacho Dinámico

// Úsalos cuando necesites colecciones heterogéneas o sistemas de plugins
trait Handler: Send + Sync {
    fn handle(&self, request: &Request) -> Response;
}

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

// Usa genéricos para rendimiento (monomorfización)
fn fast_process<H: Handler>(handler: &H, request: &Request) -> Response {
    handler.handle(request)
}

Patrón Newtype para Seguridad de Tipos

// Bien: Tipos distintos evitan mezclar argumentos
struct UserId(u64);
struct OrderId(u64);

fn get_order(user: UserId, order: OrderId) -> Result<Order> {
    // No se pueden intercambiar accidentalmente los IDs de usuario y pedido
    todo!()
}

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

Structs y Modelado de Datos

Patrón Builder para Construcción Compleja

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 y Closures

Prefiere Cadenas de Iteradores sobre Bucles Manuales

// Bien: Declarativo, perezoso, componible
let active_emails: Vec<String> = users.iter()
    .filter(|u| u.is_active)
    .map(|u| u.email.clone())
    .collect();

// Mal: Acumulación imperativa
let mut active_emails = Vec::new();
for user in &users {
    if user.is_active {
        active_emails.push(user.email.clone());
    }
}

Usa collect() con Anotación de Tipo

// Colecciona en 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();

// Colecciona Results — cortocircuita en el primer error
let parsed: Result<Vec<i32>, _> = strings.iter().map(|s| s.parse()).collect();

Concurrencia

Arc<Mutex<T>> para Estado Compartido Mutable

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("hilo de trabajo panicó");
}

Canales para Paso de Mensajes

use std::sync::mpsc;

let (tx, rx) = mpsc::sync_channel(16); // Canal acotado con contrapresión

for i in 0..5 {
    let tx = tx.clone();
    std::thread::spawn(move || {
        tx.send(format!("mensaje {i}")).expect("receptor desconectado");
    });
}
drop(tx); // Cierra el emisor para que el iterador de rx termine

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

Async con 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("solicitud agotó el tiempo de espera")?
    .context("solicitud falló")?;

    response.text().await.context("fallo al leer el cuerpo")
}

// Lanza tareas concurrentes
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!("tarea lanzada panicó: {e}")));
    }
    results
}

Código Inseguro (unsafe)

Cuándo unsafe es Aceptable

// Aceptable: Límite FFI con invariantes documentados (Rust 2024+)
/// # Seguridad
/// `ptr` debe ser un puntero válido y alineado a un `Widget` inicializado.
unsafe fn widget_from_raw<'a>(ptr: *const Widget) -> &'a Widget {
    // SEGURIDAD: el llamante garantiza que ptr es válido y está alineado
    unsafe { &*ptr }
}

// Aceptable: Ruta crítica de rendimiento con prueba de corrección
// SEGURIDAD: index siempre es < len debido al límite del bucle
unsafe { slice.get_unchecked(index) }

Cuándo unsafe NO es Aceptable

// Mal: Usar unsafe para evitar el borrow checker
// Mal: Usar unsafe por conveniencia
// Mal: Usar unsafe sin un comentario de Seguridad
// Mal: Transmutar entre tipos no relacionados

Sistema de Módulos y Estructura de Crate

Organiza por Dominio, No por Tipo

my_app/
├── src/
│   ├── main.rs
│   ├── lib.rs
│   ├── auth/          # Módulo de dominio
│   │   ├── mod.rs
│   │   ├── token.rs
│   │   └── middleware.rs
│   ├── orders/        # Módulo de dominio
│   │   ├── mod.rs
│   │   ├── model.rs
│   │   └── service.rs
│   └── db/            # Infraestructura
│       ├── mod.rs
│       └── pool.rs
├── tests/             # Pruebas de integración
├── benches/           # Benchmarks
└── Cargo.toml

Visibilidad — Expón Mínimamente

// Bien: pub(crate) para compartir internamente
pub(crate) fn validate_input(input: &str) -> bool {
    !input.is_empty()
}

// Bien: Re-exporta API pública desde lib.rs
pub mod auth;
pub use auth::AuthMiddleware;

// Mal: Hacer todo pub
pub fn internal_helper() {} // Debería ser pub(crate) o privada

Integración con Herramientas

Comandos Esenciales

# Compilar y verificar
cargo build
cargo check              # Verificación rápida de tipos sin generar código
cargo clippy             # Lints y sugerencias
cargo fmt                # Formatear código

# Pruebas
cargo test
cargo test -- --nocapture    # Mostrar salida de println
cargo test --lib             # Solo pruebas unitarias
cargo test --test integration # Solo pruebas de integración

# Dependencias
cargo audit              # Auditoría de seguridad
cargo tree               # Árbol de dependencias
cargo update             # Actualizar dependencias

# Rendimiento
cargo bench              # Ejecutar benchmarks

Referencia Rápida: Modismos de Rust

ModismoDescripción
Presta, no clonesPasa &T en lugar de clonar a menos que necesites ownership
Haz que los estados ilegales sean irrepresentablesUsa enums para modelar solo estados válidos
? sobre unwrap()Propaga errores, nunca hagas panic en librería/producción
Parsea, no validesConvierte datos no estructurados a structs tipados en el límite
Newtype para seguridad de tiposEnvuelve primitivas en newtypes para evitar intercambios de argumentos
Prefiere iteradores sobre buclesLas cadenas declarativas son más claras y a menudo más rápidas
#[must_use] en ResultsAsegura que los llamantes manejen los valores de retorno
Cow para ownership flexibleEvita asignaciones cuando el préstamo es suficiente
Matching exhaustivoSin comodín _ para enums críticos de negocio
Superficie pub mínimaUsa pub(crate) para APIs internas

Anti-Patrones a Evitar

// Mal: .unwrap() en código de producción
let value = map.get("key").unwrap();

// Mal: .clone() para satisfacer al borrow checker sin entender por qué
let data = expensive_data.clone();
process(&original, &data);

// Mal: Usar String cuando &str es suficiente
fn greet(name: String) { /* debería ser &str */ }

// Mal: Box<dyn Error> en librerías (usa thiserror en su lugar)
fn parse(input: &str) -> Result<Data, Box<dyn std::error::Error>> { todo!() }

// Mal: Ignorar advertencias must_use
let _ = validate(input); // Descartar silenciosamente un Result

// Mal: Bloquear en contexto async
async fn bad_async() {
    std::thread::sleep(Duration::from_secs(1)); // ¡Bloquea el executor!
    // Usa: tokio::time::sleep(Duration::from_secs(1)).await;
}

Recuerda: Si compila, probablemente sea correcto — pero solo si evitas unwrap(), minimizas unsafe, y dejas que el sistema de tipos trabaje para ti.

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.

Skills relacionados