Derivando Traits
#[derive(...)] pede ao compilador para auto-implementar traits padrão para structs e enums com lógica correta campo a campo.
Receita
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
struct UserId(u64);
#[derive(Debug, serde::Serialize, serde::Deserialize)]
struct User {
id: UserId,
name: String,
}Quando usar isso: Implementação rápida de Debug, Clone, igualdade, ordenação e serde quando a semântica dos campos corresponde ao comportamento derivado.
Exemplo de Trabalho
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
enum Priority { Low, Medium, High }
fn main() {
use std::collections::BTreeSet;
let mut set = BTreeSet::new();
set.insert(Priority::High);
set.insert(Priority::Low);
println!("{:?}", set);
}O que isso demonstra:
Ordderivado em enums requer ordenação de discriminanteHash+Eqhabilitam chavesHashSet/HashMapCopyadicionado quando todos os campos sãoCopy- Traits personalizados ainda precisam de
implmanual
Análise Profunda
Derives Comuns
| Trait | Propósito |
|---|---|
Debug | Formatação {:?} |
Clone | Duplicação .clone() |
Copy | Cópia implícita (bitwise na pilha) |
PartialEq/Eq | Igualdade == |
PartialOrd/Ord | Comparações de ordenação |
Hash | Hash maps/sets |
Default | Default::default() |
#[derive(Default)]
Escolhe a primeira variante para enums ou requer o atributo #[default] na variante escolhida (Rust 1.62+).
Não Pode Derivar
Display, Drop, From para lógica arbitrária - impl manual ou crates separados (thiserror, strum).
Armadilhas
- Derivar
Eqem floats - Impossível. Correção: Use inteiros oupartial_cmpmanualmente. - Derivar
Ordem floats - Não é uma ordem total. Correção:implmanual com tipo wrapperpartial_cmp. - Custo de
Clonealto oculto - Derive clona todos os campos. Correção: UseArcinternamente ou eviteClone. Hashderivado muda com a ordem dos campos - Reordenar campos muda o hash (mesmo tipo). Correção: Versionamento de esquema estável para hashes persistidos.- Manual + derive conflitantes - Não pode ter ambos. Correção: Remova o derive para esse trait.
Alternativas
| Alternativa | Use Quando | Não Use Quando |
|---|---|---|
impl Manual | Igualdade/exibição personalizada | Comportamento estrutural padrão |
crate derive_more | Newtypes repetitivos | Derive padrão é suficiente |
thiserror/strum | Erros/strings de enum | Structs simples |
serde derive | Serialização JSON/config | Nenhuma serialização necessária |
FAQs
Onde o derive se expande?
O compilador gera `impl` em tempo de compilação - use `cargo expand` para inspecionar.Derive em genéricos?
`#[derive(Debug)] struct Wrapper<T>(T)` requer `T: Debug`.Atributos auxiliares?
`#[serde(skip)]`, `#[default]`, `#[derivative(...)]` com crates adicionais.Enums podem derivar `Hash`?
Sim, se todas as cargas úteis de variante forem hasheáveis.`Copy` + `Clone` juntos?
Comum - `Copy` requer `Clone`.Derivar `Debug` para segredos?
Vaza em logs - `Debug` personalizado com campos expurgados.Derive de Union?
Derives são limitados em unions - principalmente `unsafe` manual.Newtype transparente?
`#[repr(transparent)]` + derive preserva o layout para FFI.Ordem de múltiplos derives?
A ordem entre traits no atributo não importa.Performance?
Métodos derivados são inline; igual a implementações estruturais escritas à mão.Relacionados
Versões da Stack: Esta página foi escrita para Rust 1.97.0 (edição 2024), Tokio 1.x, Axum 0.8, serde 1.0, sqlx 0.8, clap 4, e Polars 0.46+.