Source profileQuality 74/100Review permissions

affaan-m/ECC/docs/es/skills/rust-patterns/SKILL.md

rust-patterns

Patrones idiomáticos de Rust, ownership, manejo de errores, traits, concurrencia y buenas prácticas para construir aplicaciones seguras y eficientes.

Source repository stars
234,327
Declared platforms
0
Static risk flags
1
Last source update
2026-07-27
Source checked
2026-07-28

Decision brief

What it does—and where it fits

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

Best for

    Not for

    • Tasks that require unconfirmed production actions or broad system permissions.
    • Environments where the pinned source and install steps cannot be inspected.

    Compatibility matrix

    Platform support, with evidence labels

    PlatformStatusEvidenceWhat to check
    CodexNot declaredNo explicit evidencePortability before use
    Claude CodeNot declaredNo explicit evidencePortability before use
    CursorNot declaredNo explicit evidencePortability before use
    Gemini CLINot declaredNo explicit evidencePortability before use
    Open the compatibility checker

    Installation

    Inspect first. Install second.

    The source command is displayed only when detected. A safe inspection prompt is always available so your agent can explain every action before execution.

    Source-detected install commandSource
    npx skills add https://github.com/affaan-m/ECC --skill "docs/es/skills/rust-patterns"
    Safe inspection promptEditorial

    Inspect the Agent Skill "rust-patterns" from https://github.com/affaan-m/ECC/blob/4e973d3eaf92d97f8d2e2d8abb39d8bdc8711b38/docs/es/skills/rust-patterns/SKILL.md at commit 4e973d3eaf92d97f8d2e2d8abb39d8bdc8711b38. List every install step, command, network request, credential, file read/write, external action, and rollback step. Explain whether it fits my task. Do not install or execute anything until I approve.

    Workflow

    What the source asks the agent to do

    1. 01

      Cuándo Usar

      Escribir código Rust nuevo

      Escribir código Rust nuevoRevisar código RustRefactorizar código Rust existente
    2. 02

      Cómo Funciona

      Este skill refuerza las convenciones idiomáticas de Rust en seis áreas clave: ownership y borrowing para prevenir data races en tiempo de compilación, propagación de errores con Result/? usando thiserror para bibliotecas y anyhow para aplicaciones, enums y pattern matching exhau…

      Este skill refuerza las convenciones idiomáticas de Rust en seis áreas clave: ownership y borrowing para prevenir data races en tiempo de compilación, propagación de errores con Result/? usando thiserror para biblioteca…
    3. 03

      Principios Fundamentales

      El sistema de ownership de Rust previene data races y bugs de memoria en tiempo de compilación.

      El sistema de ownership de Rust previene data races y bugs de memoria en tiempo de compilación.
    4. 04

      1. Ownership y Borrowing

      El sistema de ownership de Rust previene data races y bugs de memoria en tiempo de compilación.

      El sistema de ownership de Rust previene data races y bugs de memoria en tiempo de compilación.
    5. 05

      Usar Cow para Ownership Flexible

      Review the “Usar Cow para Ownership Flexible” section in the pinned source before continuing.

      Review and apply the “Usar Cow para Ownership Flexible” source section.

    Permission review

    Static risk signals and limitations

    Runs scripts

    medium · line 432

    The documentation asks the agent to run terminal commands or scripts.

    cargo build

    Runs scripts

    medium · line 433

    The documentation asks the agent to run terminal commands or scripts.

    cargo check # Verificación de tipos rápida sin codegen

    Evidence record

    Why each signal appears

    EvidenceSourceComputedTestedEditorial
    SignalValueEvidence typeMeaning
    Quality score74/100ComputedDocumentation, specificity, maintenance, and trust rules
    Repository stars234,327SourceRepository attention, not individual Skill quality
    Compatibility0 platformsSourceDeclared in the catalog source record
    Usage guideautomated source guideEditorialGenerated or reviewed according to the visible evidence level

    Pinned source

    Provenance and original SKILL.md

    Repository
    affaan-m/ECC
    Skill path
    docs/es/skills/rust-patterns/SKILL.md
    Commit
    4e973d3eaf92d97f8d2e2d8abb39d8bdc8711b38
    License
    MIT
    Collected
    2026-07-28
    Default branch
    main
    View the original SKILL.md

    Patrones de Desarrollo Rust

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

    Cuándo Usar

    • Escribir código Rust nuevo
    • Revisar código Rust
    • Refactorizar código Rust existente
    • Diseñar la estructura de crates y la organización de módulos

    Cómo Funciona

    Este skill refuerza las convenciones idiomáticas de Rust en seis áreas clave: ownership y borrowing para prevenir data races en tiempo de compilación, propagación de errores con Result/? usando thiserror para bibliotecas y anyhow para aplicaciones, enums y pattern matching exhaustivo para hacer imposibles los estados inválidos, traits y genéricos para abstracciones de costo cero, concurrencia segura con 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 data races y bugs de memoria en tiempo de compilación.

    // Bien: Pasar referencias cuando no se necesita el ownership
    fn process(data: &[u8]) -> usize {
        data.len()
    }
    
    // Bien: Tomar ownership solo cuando se necesita 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(); // Costoso — solo tomar prestado
        cloned.len()
    }
    

    Usar 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

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

    // Bien: Propagar 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!("failed to read config from {path}"))?;
        let config: Config = toml::from_str(&content)
            .with_context(|| format!("failed to parse config from {path}"))?;
        Ok(config)
    }
    
    // Mal: Causa panic 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 Biblioteca con thiserror, Errores de Aplicación con anyhow

    // Código de biblioteca: errores estructurados y tipados
    use thiserror::Error;
    
    #[derive(Debug, Error)]
    pub enum StorageError {
        #[error("record not found: {id}")]
        NotFound { id: String },
        #[error("connection failed")]
        Connection(#[from] std::io::Error),
        #[error("invalid data: {0}")]
        InvalidData(String),
    }
    
    // Código de aplicación: manejo de errores flexible
    use anyhow::{bail, Result};
    
    fn run() -> Result<()> {
        let config = load_config("app.toml")?;
        if config.workers == 0 {
            bail!("worker count must be > 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

    Modelar Estados con Enums

    // Bien: Los 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 en Lógica de Negocio

    // Bien: Manejar cada variante explícitamente
    match command {
        Command::Start => start_service(),
        Command::Stop => stop_service(),
        Command::Restart => restart_service(),
        // Agregar una nueva variante fuerza su manejo 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

    Aceptar Genéricos, Retornar 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: Bounds de traits para múltiples restricciones
    fn process<T: Display + Send + 'static>(item: T) -> String {
        format!("processed: {item}")
    }
    

    Trait Objects para Dispatch Dinámico

    // Usar cuando se necesitan colecciones heterogéneas o sistemas de plugins
    trait Handler: Send + Sync {
        fn handle(&self, request: &Request) -> Response;
    }
    
    struct Router {
        handlers: Vec<Box<dyn Handler>>,
    }
    
    // Usar genéricos cuando se necesita 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 previenen mezclar argumentos
    struct UserId(u64);
    struct OrderId(u64);
    
    fn get_order(user: UserId, order: OrderId) -> Result<Order> {
        // No se pueden intercambiar accidentalmente user ID y order ID
        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

    Preferir Cadenas de Iteradores sobre Bucles Manuales

    // Bien: Declarativo, lazy, composable
    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());
        }
    }
    

    Usar collect() con Anotación de Tipo

    // Recolectar 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();
    
    // Recolectar Results — cortocircuita al primer error
    let parsed: Result<Vec<i32>, _> = strings.iter().map(|s| s.parse()).collect();
    

    Concurrencia

    Arc<Mutex<T>> para Estado Mutable Compartido

    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 poisoned");
            *num += 1;
        })
    }).collect();
    
    for handle in handles {
        handle.join().expect("worker thread panicked");
    }
    

    Canales para Paso de Mensajes

    use std::sync::mpsc;
    
    let (tx, rx) = mpsc::sync_channel(16); // Canal acotado con backpressure
    
    for i in 0..5 {
        let tx = tx.clone();
        std::thread::spawn(move || {
            tx.send(format!("message {i}")).expect("receiver disconnected");
        });
    }
    drop(tx); // Cerrar el sender para que el iterador 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("request timed out")?
        .context("request failed")?;
    
        response.text().await.context("failed to read body")
    }
    
    // Lanzar 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!("spawned task panicked: {e}")));
        }
        results
    }
    

    Código Unsafe

    Cuándo Unsafe Es Aceptable

    // Aceptable: Frontera FFI con invariantes documentados (Rust 2024+)
    /// # Safety
    /// `ptr` must be a valid, aligned pointer to an initialized `Widget`.
    unsafe fn widget_from_raw<'a>(ptr: *const Widget) -> &'a Widget {
        // SAFETY: el llamador garantiza que ptr es válido y alineado
        unsafe { &*ptr }
    }
    
    // Aceptable: Ruta crítica de rendimiento con prueba de corrección
    // SAFETY: index is always < len due to the loop bound
    unsafe { slice.get_unchecked(index) }
    

    Cuándo Unsafe NO Es Aceptable

    // Mal: Usar unsafe para evadir el borrow checker
    // Mal: Usar unsafe por conveniencia
    // Mal: Usar unsafe sin un comentario Safety
    // Mal: Hacer transmute entre tipos no relacionados
    

    Sistema de Módulos y Estructura de Crates

    Organizar 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 — Exponer el Mínimo

    // Bien: pub(crate) para compartir internamente
    pub(crate) fn validate_input(input: &str) -> bool {
        !input.is_empty()
    }
    
    // Bien: Re-exportar la 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 privado
    

    Integración con Herramientas

    Comandos Esenciales

    # Construir y verificar
    cargo build
    cargo check              # Verificación de tipos rápida sin codegen
    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 Rust

    ModismoDescripción
    Tomar prestado, no clonarPasar &T en lugar de clonar a menos que se necesite el ownership
    Hacer estados ilegales irrepresentablesUsar enums para modelar solo estados válidos
    ? en lugar de unwrap()Propagar errores, nunca causar panic en biblioteca/producción
    Parsear, no validarConvertir datos no estructurados a structs tipados en la frontera
    Newtype para seguridad de tiposEnvolver primitivos en newtypes para prevenir intercambio de argumentos
    Preferir iteradores sobre buclesLas cadenas declarativas son más claras y frecuentemente más rápidas
    #[must_use] en ResultsAsegurar que los llamadores manejen los valores de retorno
    Cow para ownership flexibleEvitar asignaciones cuando el borrowing es suficiente
    Matching exhaustivoSin comodín _ para enums críticos de negocio
    Superficie pub mínimaUsar 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 el 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 bibliotecas (usar thiserror en su lugar)
    fn parse(input: &str) -> Result<Data, Box<dyn std::error::Error>> { todo!() }
    
    // Mal: Ignorar advertencias must_use
    let _ = validate(input); // Descartando silenciosamente un Result
    
    // Mal: Bloquear en contexto async
    async fn bad_async() {
        std::thread::sleep(Duration::from_secs(1)); // ¡Bloquea el executor!
        // Usar: tokio::time::sleep(Duration::from_secs(1)).await;
    }
    

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

    Alternatives

    Compare before choosing