Variáveis, Mutabilidade e Shadowing
let cria vinculações. Imutabilidade é o padrão; mut opta pela reatribuição. Shadowing permite reutilizar um nome com um novo tipo ou valor sem tornar tudo mutável.
Receita
const MAX_RETRIES: u32 = 3;
fn main() {
let input = "42";
let input: u32 = input.parse().unwrap();
let mut attempts = 0;
attempts += 1;
println!("parseado {input}, tentativa {attempts}, máximo {MAX_RETRIES}");
}Quando usar isso: Sempre que precisar de estado local claro. Prefira vinculações let imutáveis e shadowing em vez de espalhar mut por toda parte.
Exemplo Funcional
const DEFAULT_PORT: u16 = 8080;
fn parse_port(raw: &str) -> u16 {
let raw = raw.trim();
let port: u16 = raw.parse().expect("porta deve ser um número");
port
}
fn main() {
let mut log_level = "info";
log_level = "debug";
let port = parse_port(" 3000 ");
println!("porta={port}, log={log_level}, padrão={DEFAULT_PORT}");
}O que isso demonstra:
constpara constantes de tempo de compilação com tipos explícitos- Shadowing de
rawapós o trim semmut mutapenas onde a reatribuição é necessária (log_level)- Pipeline de análise que reatribui o mesmo nome com um novo tipo
Análise Detalhada
Como Funciona
letintroduz uma nova vinculação no escopo atual- Vinculações imutáveis não podem ser reatribuídas (
x = 1falha) mutpermite a reatribuição da própria vinculação- Shadowing cria uma nova vinculação que oculta a anterior no mesmo escopo
let vs const vs static
| Forma | Avaliado | Tipo exigido | Uso |
|---|---|---|---|
let | Tempo de execução | Inferido ou anotado | Variáveis locais |
const | Tempo de compilação | Obrigatório | Constantes em nível de módulo |
static | Tempo de execução (endereço fixo) | Obrigatório | Singletons globais, FFI |
const KB: u32 = 1024;
static APP_NAME: &str = "myapp";Shadowing na Prática
Shadowing é comum em cadeias de análise:
let spaces = " ";
let spaces = spaces.len(); // agora usize, não &strAo contrário de mut, shadowing pode mudar o tipo porque cada let é uma nova vinculação.
Notas do Rust
let (x, y) = (1, 2);
let [first, ..] = [10, 20, 30];A desestruturação em vinculações let desempacota tuplas, arrays e structs em uma única etapa.
Armadilhas
- Usar
mutquando shadowing é suficiente - Pipelines de análise se tornam mais difíceis de seguir. Correção: Use shadowing comlet parsed = input.parse()?em vez de mutar um buffer de string. - Confundir mutabilidade de vinculação com mutabilidade interna -
let x = Rc::new(RefCell::new(0))não precisa demutemxpara chamarborrow_mut. Correção: Entenda quemuté sobre a vinculação, não sobre o conteúdo do heap. - Constantes em caminhos críticos com valores de tempo de execução -
constnão pode usarString::fromem tempo de execução. Correção: Useconstpara literais; usestaticoulazy_static/OnceLockpara inicialização em tempo de execução. - Shadowing oculta bugs - Reutilizar nomes agressivamente obscurece qual valor está ativo. Correção: Use shadowing apenas em pipelines curtos; use nomes distintos em funções longas.
- Vinculações de underscore descartam intencionalmente -
let _ = expensive();ainda executa a expressão. Correção: Prefira_apenas quando o efeito colateral ou o descarte for intencional.
Alternativas
| Alternativa | Use Quando | Não Use Quando |
|---|---|---|
Shadowing (reutilização de let) | Pipelines de análise/transformação, mudanças de tipo | Funções longas onde a reutilização de nomes confunde os leitores |
Vinculação mut | Contadores de loop, construtores incrementais | A maioria dos valores locais que são definidos uma vez |
const | Números mágicos, limites fixos | Valores computados em tempo de execução a partir da configuração |
Cell/RefCell | Mutação compartilhada por trás de vinculação imutável | Você pode usar &mut com acesso exclusivo |
FAQs
Por que a imutabilidade é o padrão?
Torna o fluxo de dados mais fácil de raciocinar e permite que o verificador de empréstimos prove a segurança. A mutação é explícita via mut.
Posso fazer shadowing de uma vinculação `mut`?
Sim. let mut x = 1; let x = 2; cria uma nova vinculação imutável que oculta a mutável.
O `const` vive na pilha?
Valores const são incorporados em tempo de compilação. Eles não ocupam espaço na pilha como variáveis em tempo de execução.
Qual é a diferença entre `static` e `const`?
static tem um endereço de memória fixo para a duração do programa. const é um valor de tempo de compilação copiado onde é usado.
Constantes podem ser públicas?
Sim. pub const TIMEOUT_MS: u64 = 5000; é comum em crates de biblioteca.
Shadowing é o mesmo que reatribuição de variável?
Não. Shadowing cria uma nova vinculação. Reatribuição (mut) atualiza a mesma vinculação.
Posso desestruturar em `let`?
Sim. let Point { x, y } = point; e let Some(v) = opt else { return }; (let-else) são idiomáticos.
Por que `let _x = value` importa para movimentos?
Mesmo vinculações não utilizadas podem mover a propriedade, a menos que o tipo seja Copy. Use o prefixo _ se você intencionalmente ignorar um valor movido.
Parâmetros de função podem ser `mut`?
Sim, mas isso permite apenas reatribuir a vinculação de parâmetro local. Não afeta o chamador.
Globais devem ser `static mut`?
Evite static mut. Prefira OnceLock, Mutex ou dados const. static mut requer unsafe para ler/escrever.
Relacionados
- Rust Basics - primeira visão geral da linguagem
- Scalar & Compound Types - tipos por trás das vinculações
- The Type System & Inference - anotações e inferência
- Ownership Preview - como os movimentos interagem com
let
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+.