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:
- Cada valor em Rust possui uma variável chamada seu proprietário.
- Só pode haver um proprietário por vez.
- 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:
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:
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:
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
Declare uma String s1 contendo o texto 'hello'. Atribua s1 a s2 (para mover a propriedade). Finalmente, imprima s2 usando println!.
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
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.
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
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.
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