Genéricos
Genéricos parametrizam tipos e funções para que uma implementação funcione para muitos tipos concretos, mantendo a segurança de tipos e custo zero.
Receita
fn largest<T: PartialOrd>(list: &[T]) -> &T {
list.iter().max_by(|a, b| a.partial_cmp(b).unwrap()).unwrap()
}
struct Wrapper<T>(T);
impl<T: std::fmt::Debug> Wrapper<T> {
fn debug(&self) { println!("{:?}", self.0); }
}Quando usar isso: Contêineres, algoritmos e APIs reutilizáveis entre tipos sem o overhead de dyn.
Exemplo de Trabalho
struct Page<T> { items: Vec<T>, page: u32 }
impl<T> Page<T> {
fn new(items: Vec<T>) -> Self {
Self { items, page: 1 }
}
fn len(&self) -> usize { self.items.len() }
}
fn main() {
let p = Page::new(vec![1, 2, 3]);
println!("{}", p.len());
}O que isso demonstra:
- Struct genérica
Page<T> - Métodos disponíveis para qualquer
T - Monomorfização gera código especializado por
T - Sem tempo de execução de apagamento de tipo, a menos que
dyn
Mergulho Profundo
Parâmetros Genéricos
Funções, structs, enums, impls e traits aceitam parâmetros de tipo <T>, parâmetros de const <const N: usize> e lifetimes 'a.
Turbofish
let v = Vec::<i32>::new();
let s = "42".parse::<u32>().unwrap();Genéricos de Constante
struct Buffer<const N: usize> { data: [u8; N] }Armadilhas
- Inchaço de monomorfização - Muitos
Tinflacionam o tamanho do binário. Correção: Despacho dinâmicodyn Traitou apagamento de tipo na fronteira. - Limites de trait ausentes -
Tnão tem métodos. Correção: Adicionar limitesT: Trait. - APIs excessivamente genéricas - Difíceis de ler. Correção: Tipos concretos na fronteira do aplicativo, genéricos dentro da biblioteca.
- Limites de inferência de genéricos de constante - Às vezes precisam de
::<N>explícito. Correção: Anotar parâmetro de constante. - Combinação de lifetime e parâmetros de tipo - Complexidade da assinatura. Correção: Formatação da cláusula
where.
Alternativas
| Alternativa | Usar Quando | Não Usar Quando |
|---|---|---|
dyn Trait | Heterogeneidade em tempo de execução | Caminho crítico precisa de inline |
| Macros | Gerar código por tipo | Genéricos expressáveis |
enum de tipos | Conjunto fechado de variantes | T de extremidade aberta |
| Alias de tipo | Simplificar genéricos longos | Apenas uma instanciação é usada |
FAQs
Custo em tempo de execução?
Monomorfizado - sem informações de tipo em tempo de execução, a menos que `dyn`.Quantos parâmetros de tipo?
Sem limite rígido; a legibilidade geralmente para em poucos.Enums genéricos?
`enum E<T> { Some(T), None }` é `Option`.impl struct genérica?
`impl<T> Foo<T> { }` métodos inerentes.Parâmetros de tipo padrão?
`struct S<T = u32>(T)`.Tipos associados vs genéricos?
Tipos associados um por impl; genéricos mais flexíveis por fn.Variância?
Avançado - a variância de lifetimes importa para subtyping.Lint genérico?
clippy type_complexity avisa sobre assinaturas longas.genéricos no_std?
Mesmo sistema sem coleções std.genéricos async?
Funções async genéricas sobre `T: Trait` são comuns.Relacionados
- Limites de Trait
- Noções Básicas de Traits
- Despacho Estático vs Dinâmico
- Tipos e Constantes Associados
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+.