DEV Community

Higor Diego
Higor Diego

Posted on

Rust - Ownership ?

alt text

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  
*/

Enter fullscreen mode Exit fullscreen mode

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
*/

Enter fullscreen mode Exit fullscreen mode

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");
}

Enter fullscreen mode Exit fullscreen mode

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;
}

Enter fullscreen mode Exit fullscreen mode

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

*/

Enter fullscreen mode Exit fullscreen mode

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
*/


Enter fullscreen mode Exit fullscreen mode

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
*/

Enter fullscreen mode Exit fullscreen mode

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á
*/

Enter fullscreen mode Exit fullscreen mode

Então galera é isso, espero que tenham gostado até a próxima.

Discussion (0)