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).