Rust - Ownership ?
Higor Diego
Posted on September 26, 2021
Todos os programas têm que decidir de que forma vão utilizar a memória do computador durante sua execução.
Existe linguagens que abordam o garbage collection (coleta de lixo) que simplesmente buscam espaço em memória que não estão em uso naquele momento.
Outra abordagem em outras linguagens é que, o programador deve alocar o espaço em memória e liberar.
No Rust usa uma abordagem diferente que é memória gerenciada através de um sistema de posse que contém um conjunto de regras que isso é verificado em tempo de compilação.
Regras de Owneship
- Cada valor em Rust possui uma variável que é dita seu owner (sua dona).
- Pode apenas haver um owner por vez.
- Quando o owner sai fora de escopo, o valor será destruído.
Para que possamos ilustrar o conjunto de regras precisamos de um tipo de dados que seja complexo abordagem porque esses dados são armazenados na pilha e assim retirada quando o escopo acaba.
Vamos para o exemplo.
fn main() {
let x = String::from("Higor Diego");
println!("{}", x);
}
/*
Higor Diego
*/
Em post anteriores vimos string literais onde o valor da string é fixado elas são convenientes mas se adequam em situação que queremos textos em nossos programas. Uma das característica delas que são imutáveis.
No exemplo usamos o String::From o :: é um operador que nos permiti indicar o namespace da função from que se caracteriza como uma string.
Vamos para o exemplo abaixo.
fn main() {
let mut x = String::from("Higor Diego");
x.push_str(" é o meu nome");
println!("{}", x);
}
/*
Higor Diego é o meu nome
*/
Fica uma pergunta no ar, porque as String podem ser alterada e as literais não? O detalhe disso é como eles lidam com a memória.
Quando uma String literal é declarada já está explícito o conteúdo com isso injetado no software assim fazendo elas serem rápidas.
Segue o exemplo.
{
let x = String::from("escopo");
}
No exemplo acima temos um escopo que é declarado pela chaves dentro dele temos uma variável x que é uma string após o fechamento da chaves a variável não é mais valida pois o escopo fechou.
No Rust quando a variável sai do escopo automaticamente chamamos uma função especial chamada drop. Parece simples mas quando temos múltiplas variáveis como seria ?
Segue o exemplo.
fn main() {
let number_1 = 10;
let number_2 = number_1;
}
No caso acima temos uma variável chamada number_1 que recebe um valor de 10 e temos number_2 que associada a variável anterior. Temos duas variáveis com o mesmo valor isso acontece porque números possuem um tamanho fixo.
No caso de uma String como seria ?
fn main() {
let n_1 = String::from("higor");
let n_2 = n_1;
println!("{}", n_1);
}
/*
--> main.rs:27:20
|
25 | let n_2 = n_1;
| --- value moved here
26 |
27 | println!("{}", n_1)
| ^^^ value used here after move
|
= note: move occurs because `n_1` has type `std::string::String`, which does not implement the `Copy` trait
error: aborting due to previous error
*/
Se analisar o exemplo anterior com esse, seria basicamente a mesma coisa só que existe uma diferença, porque estamos falando de "cópia rasa" e "copia profunda".
O Rust nesse exemplo está invalidando a primeira variável no lugar de chamar a "copia rasa" isso é conhecido como move. Após a locação da variável para n_2 com n_1 o Rust libera o espaço de valor da n_1 em memória e a loca n_2 no seu lugar assim invalidando a variável n_1.
Para resolução vamos utilizar uma função chamada clone() que no caso seria uma copia profunda da variável declarada.
Segue o exemplo.
fn main() {
let n_1 = String::from("higor");
let n_2 = n_1.clone();
println!("n_1: {}, n_2: {}", n_1, n_2);
}
/*
n_1: higor, n_2: higor
*/
Vamos testar o mesmo conceito com funções.
fn main() {
let x1 = retorna_string();
let x2 = x1;
println!("x1: {}, x2: {}", x1, x2);
}
fn retorna_string() -> String {
return String::from("olá");
}
/*
--> main.rs:4:30
|
3 | let x2 = x1;
| -- value moved here
4 | println!("x1: {}, x2: {}", x1, x2);
| ^^ value used here after move
|
= note: move occurs because `x1` has type `std::string::String`, which does not implement the `Copy` trait
error: aborting due to previous error
*/
Ahhhhh, mas está fácil. Para que possa corrigir só usar o clone().
Segue o exemplo.
fn main() {
let x1 = retorna_string();
let x2 = x1.clone();
println!("x1: {}, x2: {}", x1, x2);
}
fn retorna_string() -> String {
return String::from("olá");
}
*/
x1: olá, x2: olá
*/
Então galera é isso, espero que tenham gostado até a próxima.
Posted on September 26, 2021
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.