Algo más sobre referencias

Puedes ver este capítulo en YouTube en inglés

Las referencias son muy importantes en Rust. Las utiliza para asegurarse de que son seguros todos los accesos a la memoria. Ya se ha explicado anteriormente que para crear una referencia se utiliza & delante del valor:

fn main() {
    let pais = String::from("Austria");
    let ref_uno = &pais;
    let ref_dos = &pais;

    println!("{}", ref_uno);
}

El código anterior imprime Austria. pais es un String. Se crean dos referencias a pais. Estas referencias son de tipo &String, es decir son dos variables que son "referencias a String". Se pueden crear tantas referencias a paiscomo se quiera. Todas "apuntan" al mismo valor, pero son punteros diferentes.

A continuación se muestra un ejemplo sobre cómo Rust proteje el acceso a zonas de memoria erróneas:

fn return_str() -> &str {
    let pais = String::from("Austria");
    let pais_ref = &pais;
    pais_ref // ⚠️
}

fn main() {
    let pais = return_str();
}

La función return_str() crea un valor de tipo String, luego crea una referencia a dicho valor. Cuando se intenta devolver la referencia se produce un error:

error[E0106]: missing lifetime specifier
 --> src/main.rs:1:20
  |
1 | fn return_str() -> &str {
  |                    ^ expected named lifetime parameter
  |
  = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
help: consider using the `'static` lifetime
  |
1 | fn return_str() -> &'static str {
  |                    ^^^^^^^^

El valor de pais solo existe dentro de la función, al terminar de ejecutarse desaparece. Una vez la variable desaparece, el ordenador libera la memoria que ocupaba y la utiliza para otra cosa. Por eso, después de que la función termina, pais_ref apunta a una zona de memoria que ya no tiene el valor esperado y eso no es correcto. Rust previene este fallo en el código e impide que el programa compile.

Este es el efecto importante de la existencia de tipos de dato "con dueño" en Rust. En el código anterior, el valor String tiene como dueño a la variable pais, por eso se puede "prestar" a otras variables (referencias), pero cuando desaparece la variable dueña del valor, pais, la referencia también desaparece, la referencia tiene "prestado" el valor, por lo que no se puede pasar a otro "dueño".