Leçons du module (2/2)
Références et Borrowing
En Rust, passer continuellement la propriété (ownership) d'une variable à une fonction et la lui faire renvoyer peut être très fastidieux. Pour résoudre ce problème, Rust utilise les références (references).
Créer une référence à une valeur s'appelle le Borrowing (emprunt).
Références Immuables
Une référence se déclare en faisant précéder le type ou la variable du symbole &. Par défaut, les références sont immuables : elles permettent de lire la valeur mais pas de la modifier.
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
Références Mutables
Si vous avez besoin de modifier une valeur empruntée, vous devez utiliser une référence mutable via &mut. La variable d'origine doit également être déclarée mutable avec mut :
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");
}
Les Règles d'Or du Borrowing
Pour prévenir les corruptions de mémoire et les accès concurrents aux données (data races) au moment de la compilation, Rust impose deux règles fondamentales :
- Vous pouvez avoir un nombre quelconque de références immuables (
&T) à une valeur en même temps. - OU ALORS vous pouvez avoir exactement une seule référence mutable (
&mut T) à une valeur à la fois.
Vous ne pouvez absolument pas mélanger références immuables et mutables pour la même valeur dans la même portée :
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
La Portée des Références et Non-Lexical Lifetimes (NLL)
Auparavant, la portée d'une référence durait obligatoirement jusqu'à la fin du bloc dans lequel elle était créée. Aujourd'hui, le compilateur de Rust est plus intelligent grâce aux Non-Lexical Lifetimes (NLL) : la portée d'une référence se termine à la dernière ligne où elle est utilisée, pas nécessairement à la fin du bloc.
Cela rend le code suivant valide :
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
À toi de jouer
Passez une référence immuable de s1 à la fonction calculate_length à l'aide du symbole &.
Afficher l'indice
Remplacez `/* TODO \_/`par`&s1` pour passer une référence immuable à la chaîne.
Solution disponible après 3 tentatives
Rendez la variable s mutable (let mut s) et passez une référence mutable (&mut s) à la fonction change pour lui permettre de modifier la chaîne.
Afficher l'indice
Utilisez `let mut s`au lieu de`let s`et appelez`change(&mut s);`.
Solution disponible après 3 tentatives
Déclarez une variable s contenant String::from("Rust"). Créez deux références immuables distinctes r1 et r2 à s, et enfin affichez les deux références séparées par un espace en utilisant la macro println!.
Afficher l'indice
Assignez `let r1 = &s;` et `let r2 = &s;` pour obtenir deux références immuables, puis affichez-les avec `println!("{} {}", r1, r2);`.
Solution disponible après 3 tentatives