O Sistema de Tipos e Inferência
Rust é estaticamente tipado: todo valor tem um tipo conhecido em tempo de compilação. O compilador infere tipos quando possível; anotações esclarecem a intenção nos limites da API e resolvem ambiguidades.
Receita
fn main() {
let x = 10; // i32 inferido
let y: u64 = 10; // explícito
let items = vec![1, 2, 3]; // Vec<i32>
let mapped: Vec<_> = items.iter().map(|n| n * 2).collect();
println!("{x} {y} {:?}", mapped);
}Quando usar isso: Escolher tipos explícitos em APIs públicas, turbofish ::<T>, e entender por que a inferência às vezes precisa de uma dica.
Exemplo de Trabalho
use std::io::{self, BufRead};
fn read_numbers<R: BufRead>(reader: R) -> io::Result<Vec<i32>> {
let mut out = Vec::new();
for line in reader.lines() {
let n: i32 = line?.trim().parse()?;
out.push(n);
}
Ok(out)
}
fn main() -> io::Result<()> {
let stdin = io::stdin();
let nums = read_numbers(stdin.lock())?;
let sum: i32 = nums.iter().sum();
println!("sum={sum}");
Ok(())
}O que isso demonstra:
R: BufReadgenérico inferido no local da chamada?emparse()propagaParseIntErrorviaFromi32explícito no alvo deparse- Tipo de retorno
io::Result<Vec<i32>>guia as conversões de erro
Mergulho Profundo
Como a Inferência Funciona
- O compilador atribui tipos com base em restrições de atribuições, assinaturas de função e implementações de trait (
trait impls). - Literais inteiros têm o padrão
i32, floatsf64sem outras dicas. collect()frequentemente precisa de turbofish:collect::<Vec<_>>()- Erros de tipo geralmente apontam para o primeiro local onde as restrições entram em conflito.
Anotações vs. Turbofish
let v = Vec::<String>::new();
let v: Vec<String> = Vec::new();
let nums = "1 2 3".split_whitespace().map(|s| s.parse::<u32>().unwrap()).collect::<Vec<_>>();Nunca Digite !
fn exit(code: i32) -> ! {
std::process::exit(code);
}Expressões do tipo ! unificam-se com qualquer tipo em braços de match (divergentes).
Armadilhas
collect()ambíguo -let v = iter.collect();gera erro. Correção:collect::<Vec<_>>()ou anotelet v: Vec<T>.- Ambiguidade de literal numérico em genéricos -
let x: T = 1;pode falhar. Correção: UseT::from(1)ou sufixo de literal. - Anotar demais locais - Ruído sem benefício. Correção: Anote itens públicos e onde a inferência falha.
- Assumir
usize==u64-usizedepende da plataforma. Correção: Faça cast explícito para FFI/serialização. - Sombreamento altera o tipo inferido -
let x = 1; let x = "a";altera o tipo silenciosamente. Correção: Use nomes distintos em escopos longos.
Alternativas
| Alternativa | Use Quando | Não Use Quando |
|---|---|---|
Turbofish ::<T> | Parâmetro de tipo de método único | Repetido - use alias de tipo |
Alias de tipo type Id = u64 | Clareza de domínio | Primitivos de uso único |
impl Trait em retornos | Ocultar tipo concreto | Chamadores precisam de tipo nomeado |
| Wrapper Newtype | Unidades distintas | Matemática apenas interna |
FAQs
Rust é dinamicamente tipado em algum lugar?
Não em código de aplicação seguro. dyn Trait ainda é verificado estaticamente em tempo de compilação para uso de objeto trait.
A inferência pode falhar em funções recursivas?
Às vezes. Anote explicitamente o tipo de retorno em funções recursivas.
Qual é o tipo de inteiro padrão?
i32 para literais inteiros não tipados na maioria dos contextos.
let _ = expr afeta a inferência?
A expressão ainda é verificada quanto ao tipo. _ descarta a ligação, mas não as restrições de tipo.
Como closures afetam a inferência?
Os tipos de parâmetros e retorno de closures são inferidos pelo uso. Anote com |x: u32| -> u32 quando necessário.
O que é atribuição de tipo (type ascription)?
Outro nome para anotações explícitas: let x: i32 = 1.
Posso imprimir um tipo em tempo de compilação?
Não diretamente. Use std::any::type_name::<T>() em tempo de execução para depuração.
Aliases de tipo criam novos tipos?
Não. type Meters = f64 é intercambiável com f64. Use uma struct newtype para distinção.
Como a inferência interage com async?
Os tipos de saída de Future são inferidos pelo uso de .await e pela posição de retorno em async fn.
Quais ferramentas ajudam além do compilador?
rust-analyzer mostra os tipos inferidos ao passar o mouse. cargo check é a fonte da verdade.
Relacionado
- Tipos Escalares e Compostos - tipos primitivos
- Genéricos - tipos paramétricos
- Restrições de Trait (Trait Bounds) - genéricos de restrição
- Funções e Expressões - expressões de tipo de retorno
Versões da Pilha: 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+.