Saltar al contenido principal
eLearner.app
Módulo 3 · Lección 2 de 26/14 en el curso~15 min
Lecciones del módulo (2/2)

Referencias y Borrowing

En Rust, pasar continuamente la propiedad (ownership) de una variable a una función y hacer que la devuelva puede ser muy incómodo. Para resolver este problema, Rust utiliza los referencias (references).

Crear una referencia a un valor se llama Borrowing (tomar prestado).

Referencias Inmutables

Una referencia se declara anteponiendo el símbolo & al tipo o a la variable. Por defecto, las referencias son inmutables: permiten leer el valor pero no modificarlo.

Code
fn main() {
    let s1 = String::from("hello");

    // Passiamo un riferimento a s1, non l'ownership
    let len = calculate_length(&s1);

    // s1 è ancora utilizzabile qui!
    println!("La lunghezza di '{}' è {}.", s1, len);
}

fn calculate_length(s: &String) -> usize { // s è un riferimento a una String
    s.len()
} // Qui s esce dallo scope, ma poichè non possiede il valore, non succede nulla

Referencias Mutables

Si necesitas modificar un valor tomado prestado, debes usar una referencia mutable mediante &mut. La variable original también debe declararse como mutable con mut:

Code
fn main() {
    let mut s = String::from("hello");

    // Passiamo un riferimento mutabile
    change(&mut s);

    println!("{}", s); // Stampa "hello, world"
}

fn change(some_string: &mut String) {
    some_string.push_str(", world");
}

Las Reglas de Oro del Borrowing

Para prevenir corrupciones de memoria y condiciones de carrera (data races) en tiempo de compilación, Rust impone dos reglas fundamentales:

  1. Puedes tener cualquier número de referencias inmutables (&T) a un valor al mismo tiempo.
  2. O BIEN puedes tener exactamente una sola referencia mutable (&mut T) a un valor a la vez.

No puedes mezclar bajo ningún concepto referencias inmutables y mutables para el mismo valor en el mismo ámbito:

Code
let mut s = String::from("hello");

let r1 = &s; // Valido
let r2 = &s; // Valido
// let r3 = &mut s; // ERRORE DI COMPILAZIONE! Non puoi creare &mut s se s è già presa in prestito come immutabile

El Ámbito de las Referencias y Non-Lexical Lifetimes (NLL)

En el pasado, el ámbito de una referencia duraba obligatoriamente hasta el final del bloque en el que se creaba. Hoy en día, el compilador de Rust es más inteligente gracias a las Non-Lexical Lifetimes (NLL): el ámbito de una referencia termina en la última línea en la que se utiliza, no necesariamente al final del bloque.

Esto hace que el siguiente código sea válido:

Code
let mut s = String::from("hello");
let r1 = &s;
let r2 = &s;
println!("{} e {}", r1, r2); // Ultimo uso di r1 e r2. I riferimenti immutabili scadono qui!

let r3 = &mut s; // Valido! Nessun riferimento immutabile è attivo a questo punto

Pruébalo tú

Ejercicio#rust.m3.l2.e1
Intentos: 0Cargando...

Pasa una referencia inmutable de s1 a la función calculate_length usando el símbolo &.

Cargando editor...
Mostrar pista

Reemplaza `/* TODO \_/`con`&s1` para pasar una referencia inmutable a la cadena.

Solución disponible después de 3 intentos

Ejercicio#rust.m3.l2.e2
Intentos: 0Cargando...

Haz que la variable s sea mutable (let mut s) y pasa una referencia mutable (&mut s) a la función change para permitirle modificar la cadena.

Cargando editor...
Mostrar pista

Usa `let mut s`en lugar de`let s`y llama a`change(&mut s);`.

Solución disponible después de 3 intentos

Ejercicio#rust.m3.l2.e3
Intentos: 0Cargando...

Declara una variable s que contenga String::from("Rust"). Crea dos referencias inmutables distintas r1 y r2 a s, y finalmente imprime las dos referencias separadas por un espacio usando la macro println!.

Cargando editor...
Mostrar pista

Asigna `let r1 = &s;` y `let r2 = &s;` para obtener dos referencias inmutables, luego imprímelas con `println!("{} {}", r1, r2);`.

Solución disponible después de 3 intentos