Translate

martes, 18 de julio de 2023

El concepto de Ownership en Rust


En el post anterior dijimos "Rust logra esto modelando la propiedad o ownership explícitamente." Peeero no explique que es esto de la propiedad o ownership. 

Todos los enlaces de variables tienen un alcance donde son válidos y es un error usar una variable fuera de su alcance, por ejemplo :

struct Point(i32, i32);

fn main() {

    {

        let p = Point(3, 4);

        println!("x: {}", p.0);

    }

    println!("y: {}", p.1);

}

Si corremos este programa: 

$ cargo run

   Compiling hello_cargo v0.1.0 

error[E0425]: cannot find value `p` in this scope

 --> src/main.rs:8:23

  |

8 |     println!("y: {}", p.1);

  |                       ^ not found in this scope


For more information about this error, try `rustc --explain E0425`.

error: could not compile `hello_cargo` due to previous error


  • Al final del alcance, la variable se elimina y los datos se liberan.
  • Un destructor puede correr aquí para liberar recursos.
  • Decimos que la variable posee el valor.
Una asignación transferirá la propiedad entre las variables:

fn main() {
    let s1: String = String::from("Hello!");
    let s2: String = s1;
    println!("s2: {s2}");
    // println!("s1: {s1}");
}

Si corremos este programa funcionará : 

$ cargo run
   Compiling hello_cargo v0.1.0 
    Finished dev [unoptimized + debuginfo] target(s) in 0.40s
     Running `target/debug/hello_cargo`
s2: Hello!

Pero si descomentamos esta linea // println!("s1: {s1}"); . Nos lanzará un error: 

$ cargo run
   Compiling hello_cargo v0.1.0 
error[E0382]: borrow of moved value: `s1`
 --> src/main.rs:5:20
  |
2 |     let s1: String = String::from("Hello!");
  |         -- move occurs because `s1` has type `String`, which does not implement the `Copy` trait
3 |     let s2: String = s1;
  |                      -- value moved here
4 |     println!("s2: {s2}");
5 |     println!("s1: {s1}");
  |                    ^^ value borrowed here after move
  |
  = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)

For more information about this error, try `rustc --explain E0382`.
error: could not compile `hello_cargo` due to previous error

Que paso?
  • La asignación de s1 a s2 transfiere la propiedad.
  • Los datos se movieron de s1 y ya no se puede acceder a s1.
  • Cuando s1 sale del alcance, no pasa nada: no tiene propiedad.
  • Cuando s2 sale del alcance, los datos de la cadena se liberan.
  • Siempre hay exactamente un enlace de variable que posee un valor.
Esto es lo opuesto a los valores predeterminados en C++, que se copia por valor a menos que use std::move (¡y el constructor de movimiento o copia está definido!).

En Rust, la clonación de valores son explícitos (usando clon).