L’ownership en Rust est un des concepts fondamentaux du langage qui garantit la sĂ©curitĂ© de la mĂ©moire et prĂ©vient les problĂšmes de concurrence. En comprenant les rĂšgles de l’ownership et en utilisant les rĂ©fĂ©rences lorsque nĂ©cessaire, Rust nous permet dâĂ©crire un code sĂ»r et efficace. Bien que cela puisse sembler complexe au dĂ©but, une fois que lâon maĂźtrise les concepts de base, on peut se dĂ©tendre et apprĂ©cier coder en Rust đŠ
La gestion de la mémoire
Avant de parler de Rust, il me semble important de revenir sur le concept de gestion de la mĂ©moire dans un ordinateur. Venant du dĂ©veloppement web, je nâavais pas vraiment de notions sur la gestion de la mĂ©moire, ou du moins câĂ©tait assez enfoui. Logique, vu que la majoritĂ© des langages web ont Ă©tĂ© conçus pour gĂ©rer la mĂ©moire Ă la place du dĂ©veloppeur. Lorsque je me suis lancĂ© dans Rust, jâai dĂ» revenir sur des concepts de computer science, dont le fonctionnement de la mĂ©moire. Pour mâaider, comme toujours, le Book Rust ! En effet, dans Ă peu prĂšs tous les chapitres, il y a des explications complĂ©mentaires laissĂ©es pour ceux qui auraient quelques lacunes en computer science. Prenez donc le temps de lire ce contenu sur la gestion de la mĂ©moire avant de passer Ă la suite đ.
Si vous connaissez dĂ©jĂ le fonctionnement de la mĂ©moire, notamment parce que vous venez de langages tels que C / C++, et bien que cela nĂ©cessite de comprendre un nouveau concept, vous devriez apprĂ©cier de voir que Rust peut vous permettre de vous guider dans la gestion de la mĂ©moire. Et si vous me dites que vous perdez en libertĂ©, sachez que le concept de pointeur existe aussi dans Rust, et que vous pouvez aussi faire taire complĂštement les alertes de Rust Ă la compilation grĂące Ă unsafe (pas recommandĂ© Ă©videmment đ).
C’est quoi lâownership en Rust ?
En Rust, chaque variable est propriĂ©taire dâune valeur. Il ne peut y avoir quâun seul propriĂ©taire Ă la fois pour cette valeur. Lorsque le propriĂ©taire sort de la portĂ©e, la valeur est libĂ©rĂ©e.
Commençons par un exemple trÚs simple :
fn main() {
// On déclare une variable qui détient la chaßne de caractÚres "hello"
let message = String::from("hello");
println!("{}", s);
} // la variable 'message' sort de la portée et est libérée ici
Dans cet exemple, message
est une chaĂźne (String
) nouvellement créée. Lorsque message
sort de la portée à la fin de la fonction main()
, la mémoire allouée pour la chaßne est libérée automatiquement.
Voici un exemple un peu plus complexe :
fn main() {
let message = String::from("hello");
let len = calculate_length(message); // ici, la fonction prend possession de `message`
println!("La longueur de '{}' est {}.", message, len);
// On obtient une erreur car `message` a été libéré auparavant
}
fn calculate_length(s: String) -> usize {
s.len()
}
// error[E0382]: borrow of moved value: `message`
// --> src/main.rs:4:45
// |
// 2 | let message = String::from("hello");
// | ------- move occurs because `message` has type `String`, which does not implement the `Copy` trait
// 3 | let len = calculate_length(message); // ici, `len` prend possession de `message`
// | ------- value moved here
// 4 | println!("La longueur de '{}' est {}.", message, len);
// | ^^^^^^^ value borrowed here after move
Dans cet exemple, on souhaite calculer la longueur dâune chaĂźne de caractĂšres Ă lâaide de la fonction calculate_length
. Pour cela on déclare une variable message
puis on passe cette variable dans la fonction calculate_length
. Lorsque la variable passe dans la fonction, elle est libĂ©rĂ©e et nâest donc plus utilisable dans le programme. Câest pour cela que lâon obtient une erreur lorsquâon essaye de faire appel Ă la variable message
juste aprĂšs.
En Rust, câest ce quâon appelle le transfert de propriĂ©tĂ© (ownership transfer). Le transfert de propriĂ©tĂ© est le mĂ©canisme de base pour gĂ©rer les donnĂ©es. Lorsqu’une valeur est assignĂ©e Ă une autre variable, elle est transfĂ©rĂ©e de la variable source Ă la variable cible. Cela signifie que la variable source n’a plus accĂšs Ă la valeur et la variable cible devient le nouveau propriĂ©taire.
Dans lâexemple ci-dessus toujours, Ă la fin, je vous ai collĂ© le retour dâerreur quand on essaye de compiler le programme. Ici, lâerreur nous indique simplement quâon essaye dâemprunter une variable qui a âbougĂ©â (moved). En effet, si vous avez bien compris, la variable message
a effectivement âbougĂ©â lorsquâelle est âpartieâ dans la fonction calculate_length
. Cela confirme une nouvelle fois que la variable nâest plus utilisable en lâĂ©tat.
fn main() {
let x = 5;
let y = x; // x est copié, pas transféré
println!("x: {}, y: {}", x, y); // x et y sont tous les deux valides
}
Dans cet exemple, x est copié dans y, donc les deux variables restent valides.
âEmprunterâ une donnĂ©e : les rĂ©fĂ©rences
Pour partager des donnĂ©es sans transfert de propriĂ©tĂ©, Rust utilise des rĂ©fĂ©rences. Une rĂ©fĂ©rence permet Ă une variable de rĂ©fĂ©rencer la valeur d’une autre variable sans en devenir le propriĂ©taire.
Reprenons lâexemple prĂ©cĂ©dent qui produisait une erreur, et corrigeons-le :
fn main() {
let message = String::from("hello");
let len = calculate_length(&message); // ici avec le symbole "&" on indique le souhait d'emprunter la valeur
println!("La longueur de '{}' est {}.", message, len);
}
fn calculate_length(s: &String) -> usize {
s.len() // pas de transfert de propriété, s est une référence à la chaßne
}
Dans cette fonction, calculate_length
prend une référence (&String
) en argument, ce qui signifie qu’elle emprunte la chaĂźne plutĂŽt que de la possĂ©der. Ainsi, la chaĂźne reste valide mĂȘme aprĂšs l’appel de la fonction.
Â
Donc cette histoire dâownership en Rust, câest juste une histoire de propriĂ©tĂ© ! On doit essayer de se souvenir de ce que possĂšde chaque variable au fil de notre code, et puis si on se trompe, il y a toujours une remontĂ©e dâerreur qui permet de rĂ©gler le problĂšme ! JâespĂšre que tout cela semble un peu moins insurmontable, et que cela va vous donner envie de coder en Rust đŠ ! Pour aller plus loin, je vous ai aussi rĂ©alisĂ© une sĂ©lection de ressources en français pour apprendre le Rust et surtout, il y a notre belle formation Rust, accessible si vous avez des bases de programmation orientĂ©e objet. Â
Â