Immutable vs const em Rust: por que até desenvolvedores experientes se confundem?
\n\nVocê já escreveu em Rust e de repente pensou: "Pera, eu declarei uma variável com let, ela é imutável. E const também é uma constante. Qual é a diferença então?". Se sim, você não está sozinho. A pergunta "What is the difference between immutable and const variables in Rust?" no Stack Overflow tem milhares de visualizações. E não é por acaso.
À primeira vista, parece que tanto let x = 5 quanto const X: i32 = 5 fazem a mesma coisa: proíbem alterar o valor. Mas no Rust, uma linguagem onde a segurança de memória e o desempenho são prioridades, o diabo está nos detalhes. Em 2025, entender esses detalhes não é apenas teoria, mas uma necessidade para escrever código eficiente e idiomático.
Neste artigo, vamos esclarecer de uma vez por todas: qual a diferença entre uma variável imutável e uma constante, quando usar cada uma e quais são as melhores práticas atuais. Vamos nessa!
\n\n1. Entendimento básico: o que o compilador diz?
\n\nVamos começar pelo mais simples. Em Rust, as variáveis são imutáveis por padrão. Isso significa que, após atribuir um valor, você não pode sobrescrevê-lo.
\n\nfn main() {\n let x = 5;\n // x = 6; // Erro! Não é possível alterar uma variável imutável\n println!("x = {}", x);\n}\n\nAgora um exemplo com uma constante:
\n\nconst MAX_POINTS: u32 = 100_000;\n\nfn main() {\n println!("MAX_POINTS = {}", MAX_POINTS);\n}\n\nVisualmente, é parecido. Mas o compilador Rust as trata de maneiras completamente diferentes. E é aqui que a coisa fica interessante.
\n\n1.1. Diferença chave nº1: onde elas vivem?
\n\n- \n
let— declara uma variável. Ela existe na pilha (ou no heap, se forBox,String, etc.) e tem um endereço na memória. Pode ser referenciada, passada para funções, movida. \n const— declara uma constante. Ela não tem um endereço fixo na memória. O compilador inline (insere) seu valor diretamente no código no local de uso. \n
Esta é uma diferença fundamental. const não é uma variável, é um valor nomeado que é substituído em tempo de compilação.
fn main() {\n let x = 42;\n let y = &x; // Ok, pegamos uma referência para a variável\n\n const Z: i32 = 100;\n // let w = &Z; // Erro! A constante não tem endereço, não é possível pegar referência\n}\n\n2. Mergulho profundo: desempenho e semântica
\n\nAgora que sabemos sobre o "local de residência", vamos analisar outros aspectos importantes.
\n\n2.1. Tempo de vida e escopo
\nConstantes vivem no escopo global (ou dentro de uma função, mas com tempo de vida static). Elas existem durante toda a execução do programa. Podem ser declaradas fora de uma função e estarão disponíveis em qualquer lugar.
Variáveis imutáveis vivem apenas dentro do bloco (função, loop, if). Assim que o bloco termina, a memória é liberada.
const GLOBAL_CONST: i32 = 10;\n\nfn main() {\n let local_var = 20;\n // local_var vive apenas dentro de main\n}\n// local_var não existe mais\n// GLOBAL_CONST ainda está disponível\n\n2.2. Tipo e anotações
\nPara const, é obrigatório especificar o tipo de dado. Para let, o compilador infere automaticamente.
const PI: f64 = 3.14159; // Obrigatório: const NOME: Tipo = valor;\nlet pi = 3.14159; // O compilador entende que é f64\n\n2.3. Cálculo em tempo de compilação (CTFE)
\nO valor de const deve ser calculado em tempo de compilação.