Em Rust, variáveis são imutáveis por padrão. Isso é uma das características que tornam a linguagem segura e fácil de raciocinar. Quando uma variável é imutável, uma vez que um valor é vinculado a um nome, você não pode alterar esse valor. Para permitir mutabilidade, você deve explicitamente usar a palavra-chave mut. Essa abordagem evita erros comuns de programação e facilita a compreensão do fluxo de dados.

Nesta aula, exploraremos como declarar variáveis imutáveis e mutáveis, como fazer shadowing de variáveis, como definir constantes e as convenções de nomenclatura recomendadas. Cada conceito será explicado com exemplos práticos para que você possa aplicá-los em seus próprios programas.

let e let mut

A palavra-chave let é usada para declarar uma variável. Por padrão, a variável é imutável, o que significa que você não pode reatribuir um valor a ela. Se tentar, o compilador emitirá um erro. Para tornar uma variável mutável, adicione mut após let.

Exemplo de variável imutável:

let x = 5;
// x = 6; // Isso causaria um erro de compilação

Exemplo de variável mutável:

let mut y = 10;
y = 20; // Permitido porque y é mutável
println!("{}", y); // Imprime 20

A imutabilidade por padrão é uma escolha de design que ajuda a evitar bugs. Se você sabe que um valor não muda, fica mais fácil entender o código. Quando a mutabilidade é necessária, ela é explicitamente declarada.

Shadowing

Shadowing permite declarar uma nova variável com o mesmo nome de uma variável anterior. A nova variável "sombreia" a anterior, e a variável anterior não é mais acessível até que o escopo da nova termine. Ao contrário de uma variável mutável, shadowing cria uma nova variável, que pode até ser de um tipo diferente.

Exemplo de shadowing:

let x = 5;
let x = x + 1; // Agora x é 6, e a variável anterior é sombreada
{
    let x = x * 2; // Dentro deste escopo, x é 12
    println!("Dentro do escopo: {}", x); // Imprime 12
}
println!("Fora do escopo: {}", x); // Imprime 6

Shadowing é útil quando você quer transformar um valor sem precisar criar nomes diferentes. Observe que o tipo pode mudar, o que não é possível com variáveis mutáveis:

let espaco = "   ";
let espaco = espaco.len(); // espaco agora é um número (3)

Constantes

Constantes são valores que nunca mudam e são vinculados a um nome. Diferente de variáveis imutáveis, constantes devem ser declaradas com a palavra-chave const e o tipo deve ser explicitamente anotado. Constantes podem ser declaradas em qualquer escopo, inclusive no escopo global, e são válidas durante toda a execução do programa.

Exemplo de constante:

const MAX_PONTOS: u32 = 100_000;
const PI: f64 = 3.14159;

Constantes só podem ser definidas com expressões constantes (avaliadas em tempo de compilação), não com valores que só são conhecidos em tempo de execução. Use constantes para valores mágicos ou configurações que não mudam.

Convenções de nomes

Rust adota convenções de nomenclatura claras para ajudar na legibilidade do código. Para variáveis, use snake_case (letras minúsculas e underscores). Para constantes, use SCREAMING_SNAKE_CASE (letras maiúsculas e underscores). Essas convenções são recomendadas pela comunidade e seguidas pela maioria dos projetos.

Exemplos:

let nome_do_usuario = "Alice";
let mut contador = 0;
const LIMITE_MAXIMO: i32 = 100;

Seguir essas convenções torna o código mais consistente e fácil de ler para outros programadores Rust.

Boas práticas e observações finais

Prefira imutabilidade sempre que possível; isso torna o código mais previsível. Use mut apenas quando necessário. Shadowing é uma ferramenta poderosa, mas use com moderação para não confundir o leitor. Constantes são ideais para valores fixos que são usados em várias partes do código. Sempre siga as convenções de nomenclatura para manter a consistência.

Referências

Exercícios

  1. Declare uma variável imutável chamada nome com seu nome. Tente reatribuí-la a outro nome. O que acontece?

    ✓ Resposta: O compilador emitirá um erro: cannot assign twice to immutable variable. Para reatribuir, use let mut.
  2. Use shadowing para declarar uma variável x como inteiro 10, depois sombreie-a com uma string "dez". Imprima ambas dentro e fora de um escopo.

    ✓ Resposta:
    let x = 10;
    {
        let x = "dez";
        println!("Dentro: {}", x); // Imprime "dez"
    }
    println!("Fora: {}", x); // Imprime 10
  3. Declare uma constante TAXA_JUROS com valor 0.05. Tente modificar seu valor em outra parte do código. Funciona?

    ✓ Resposta: Não funciona. Constantes são imutáveis e não podem ser modificadas. Qualquer tentativa de reatribuição resultará em erro de compilação.
  4. Crie uma variável mutável contador inicializada com 0, incremente-a para 1, 2 e 3. Imprima cada valor.

    ✓ Resposta:
    let mut contador = 0;
    contador = 1;
    println!("{}", contador); // 1
    contador = 2;
    println!("{}", contador); // 2
    contador = 3;
    println!("{}", contador); // 3
  5. Declare uma constante NOME_APP com o nome do seu aplicativo favorito (em SCREAMING_SNAKE_CASE). Depois, tente usar shadowing com o mesmo nome. Isso é permitido? Por quê?

    ✓ Resposta: Sim, é permitido, pois shadowing cria uma nova variável, mesmo que o nome seja o mesmo de uma constante. A constante original não é afetada. Exemplo:
    const NOME_APP: &str = "MeuApp";
    let NOME_APP = "OutroApp"; // Shadowing: nova variável local