Pular para o conteúdo principal
Módulo 3 · Lição 1 de 25/14 no curso~15 min
Lições do módulo (1/2)

As regras de propriedade

A propriedade é a característica mais exclusiva do Rust. Ele permite que a linguagem garanta a segurança da memória sem precisar de um Garbage Collector ou forçá-lo a desalocar manualmente a memória heap (como em C ou C++).

As três regras de propriedade

O gerenciamento de memória no Rust é regido por três regras simples verificadas estritamente pelo compilador:

  1. Cada valor em Rust possui uma variável chamada seu proprietário.
  2. Só pode haver um proprietário por vez.
  3. Quando o proprietário sai do escopo, o valor é eliminado automaticamente.

Pilha vs Pilha

Para compreender a propriedade, é importante saber onde residem os dados:

  • Pilha: armazena dados de tamanho fixo conhecidos em tempo de compilação (por exemplo, números inteiros, booleanos). O acesso é extremamente rápido.
  • Heap: armazena dados de tamanho dinâmico desconhecidos em tempo de compilação (por exemplo, String). A alocação é mais lenta e requer um ponteiro armazenado na pilha.

O conceito de "mover"

Quando atribuímos uma variável alocada no heap a outra, Rust move (ou transfere) a propriedade do valor, invalidando a primeira variável:

Rust
let s1 = String::from("ciao");
let s2 = s1; // Ownership of the text moves to s2. s1 is NO longer usable!

// println!("{}", s1); // COMPILATION ERROR! s1 is "borrow of moved value"
println!("{}", s2); // Valid!

Este comportamento evita o "erro de liberação dupla" (tentar liberar a mesma memória duas vezes ao sair do escopo), pois apenas s2 irá liberar a memória.

O conceito de "clone" (cópia profunda)

Se precisarmos explicitamente copiar todo o conteúdo de um String (tanto os ponteiros de pilha quanto os dados de texto reais no heap), podemos usar o método .clone(). Isso duplica completamente os dados no heap, mantendo válidas tanto a variável original quanto a nova, ao custo de uma sobrecarga de desempenho para a nova alocação de memória:

Rust
let s1 = String::from("ciao");
let s2 = s1.clone(); // Deep copy. Both variables remain valid!
println!("s1: {}, s2: {}", s1, s2);

O conceito de "cópia"

Para tipos simples armazenados inteiramente na Pilha (como inteiros i32, booleanos bool, caracteres char), a atribuição executa uma cópia superficial automática real, o que significa que ambas as variáveis ​​permanecem válidas:

Rust
let x = 5;
let y = x; // Copies the value 5 onto the stack. Both variables are usable!
println!("x: {}, y: {}", x, y); // Valid!

Experimente você mesmo

Exercício#rust.m3.l1.e1
Tentativas: 0Carregando…

Declare uma String s1 contendo o texto 'hello'. Atribua s1 a s2 (para mover a propriedade). Finalmente, imprima s2 usando println!.

Carregando editor…
Mostrar dica

Use `let s2 = s1;` para transferir a propriedade para `s2` e imprima-o com `println!('{}', s2);`.

Solução disponível após 3 tentativas

Exercício#rust.m3.l1.e2
Tentativas: 0Carregando…

Declare uma variável inteira x com valor 5. Atribua x a y (realizando uma cópia). Finalmente, imprima x e y no mesmo println! declaração.

Carregando editor…
Mostrar dica

Faça `let y = x;` e depois imprima ambos os valores, por exemplo, `println!('{} {}', x, y);`.

Solução disponível após 3 tentativas

Exercício#rust.m3.l1.e3
Tentativas: 0Carregando…

Declare a String s1 with the value "Rust". Create a deep copy of s1 in a new variable s2 using the clone method. Finally, print both s1 and s2 separated by a space using the println! macro.

Carregando editor…
Mostrar dica

Use `let s2 = s1.clone();` to deep copy the value of `s1` into `s2`, then print them with `println!("{} {}", s1, s2);`.

Solução disponível após 3 tentativas