Contents

Rust - Variáveis Imutáveis, Variáveis Mutáveis e Shadowing

Contents

Variáveis Imutáveis e Variáveis Mutáveis

Já vou começar esse texto com algo que eu preciso chamar muito a sua antenção:

Variáveis em RUST são declaradas como imutáveis por padrão.

Mas o que isso significa? Imutável? Significa que logo que declarada, essa variável ganha um valor definido pelo programador e depois disso esse valor não pode mais ser alterado e que qualquer tentativa de alteração nesta área de memória irá gerar uma nova mensagem erro quando formos compilar o programa.

1
2
3
4
fn main() {
   let x = 4;
   x = 5;
}

O código acima gera um erro quando executamos o Cargo. E ele nos dirá que a variável x é imutável e que não podemos atribuir o valor 5 a ela.

Super interessante não? Com essa estratégia o RUST protege nosso código de erros comuns gerados por códigos muito longos onde podemos perder o controle do que deve ou não deve ser alterado. Ou atribuições não desejadas feitas por falta de atenção ou até mesmo por erro de digitação.

Mas e se por algum motivo temos certeza que precisamos de uma variável que deve ter seu valor alterado durante a execução do seu aplicativo? Quando chegamos a este cenário precisamos deixar bem claro para o RUST que sabemos o que estamos fazendo.

1
2
3
4
fn main() {
   let mut y = 5;
   y = 6;
}

Dizemos ao RUST que a variável y é mutável e que terá seu valor alterado durante o curso do seu aplicativo usando a chave ‘mut’.

O RUST também irá reclamar caso você declare uma variável como mutável e nunca altere seu valor.

Shadowing

Shadowing é um conceito interessante. Ele trás a ideia de que uma variável pode sombrear (shadow) uma variável já declarada. Isso acontece quando declaramos variáveis com o mesmo nome dentro de um bloco de nossa aplicação.

1
2
3
4
fn main() {
   let x = 6; // A
   let x = 7; // B
}

No código acima B esta sombreando A. Se formos imprimir o valor da variável X após o ‘shadowing’ acontecer neste código vamos ver que x tem valor 7 e não 6. É importante dizer que ‘shadowing’ é diferente da chave ‘mut’ pois se tentamos atribuir um novo valor a X sem utilizar a chave ‘let’ vamos receber um erro dizendo que essa variável é imutável.

1
2
3
4
5
fn main() {
   let x = 6;
   let x = 7;
   x = 8;
}

O código acima gera um erro pois x é uma variável imutável.

1
2
3
4
5
6
fn main() {
   let x = 6;     // Linha 1
   let x = 7;     // Linha 2
   let mut y = 6; // Linha 3
   y = 7;         // Linha 4
}

O código acima mostra uma outra diferença entre ‘shadowing’ e ‘mut’. Na ‘Linha 2’ estamos criando uma NOVA variável. Apesar de possuir o mesmo nome que a variável declarada na ‘Linha 1’ esses dois dados possuem endereços de memória diferente. Já na ‘Linha 4’ o valor 7 é atribuído a variável que reside no endereço de memória criado na ‘Linha 6’.

1
2
3
4
fn main() {
    let spaces = "   ";        // Linha 1
    let spaces = spaces.len(); // Linha 2
}

Um exemplo interessante do uso de ‘shadowing’ é esse código acima onde para evitar a criação de duas variáveis no nosso código ‘spaces_str’ e ‘spaces_len’ usandos o recurso de ‘shadowing’ para chegar ao resultado desejado somente com uma variável visível no código.

1
2
3
4
fn main() {
    let mut spaces = "   "; // Linha 1
    spaces = spaces.len();  // Linha 2
}

O mesmo não seria possível com a chave ‘mut’. O código acima gera um erro pois na ‘Linha 2’ tentamos atribuir um valor numérico a uma variável do tipo String. Mas você pode estar se perguntando o motivo pelo qual isso funciona com o ‘shadowing’. Lembra que falei que o nome da variável é o mesmo mas o espaço de memória é outro. Quando executamos a ‘Linha 2’ do exemplo de ‘shadowing’ estamos atribuindo um inteiro a um espaço de memória que espera um inteiro pois é o ‘let spaces’ cria esse novo espaço de memória.