Même si Rust fournit son livre Rust, j'ai eu du mal à comprendre le mot-clé mut
. Je me suis demandé : « Suis-je le seul à avoir ce problème ? » Une recherche rapide sur Google a confirmé que je n'étais pas seul.
En conséquence, j'ai décidé d'écrire cet article pour fournir une explication détaillée du mot-clé mut
. Cet article est destiné à ceux qui proviennent de langages de haut niveau comme Python ou JavaScript.
Pour créer une variable non modifiable dans Rust, écrivez simplement let x = 1337
. C'est simple. Si vous souhaitez créer une variable qui pourra être mutée ultérieurement, ajoutez simplement le mot-clé mut
après let
. Rust a une convention utile qui encourage la clarté des intentions.
L'ajout du mot-clé mut
informe les autres que cette variable sera modifiée ailleurs dans le code. D'accord.
Visualisons-le. Deux variables ici, let mut x = 1337
et let y = 42
.
Pour le moment, tout est simple. Cependant, les choses commencent à devenir un peu bouclées lors de l'utilisation de références mut
. Créons-en.
let mut x = 1337; let y = 42; let x_ref = &mut x; let y_ref = &y;
Dans le schéma donné, j'ai 4 variables, dont 2 sont des références. Les deux variables de référence sont immuables et n'ont pas de mot-clé mut
après let
, ce qui signifie que je ne peux pas changer ce vers quoi elles pointent. Cependant, je peux toujours modifier la valeur à laquelle ils font référence.
*x_ref = 777;
Si vous écrivez ceci, le compilateur Rust ne se plaindra pas et la valeur de x
(pas la référence elle-même) deviendra 777
. Cependant, il y a un carré rouge sur le schéma indiquant que x_ref
ne dispose pas de l'option de mutabilité. Alors, pourquoi puis-je modifier la valeur à laquelle elle fait référence ?
Revenons au schéma du let x_ref = &mut x
.
Le premier bloc blanc contient le nom : x_ref
. Le second m'informe sur le type stocké dans cette variable. Dans sa forme complète, sans aucune annotation de type implicite, je peux écrire ce qui suit :
let x_ref: &mut i32 = &mut x;
Je peux interpréter cela comme : créons une variable immuable nommée x_ref
qui contiendra une référence mutable à i32
et initialisons-la immédiatement avec la référence mutable à la valeur i32
dans la variable x
.
let x_ref: &mut i32 = &mut x; let mut z = 0; x_ref = &mut z; // Not allowed!
En termes de schémas, je souhaite changer la direction vers laquelle pointe la flèche dans le bloc de code ci-dessus. Cependant, même si la variable z
est mutable, je ne peux pas changer la flèche car le problème réside dans l'immuabilité de la x_ref
elle-même.
Pour changer le sens de la flèche, je dois modifier l'adresse stockée dans la variable x_ref
. Cependant, je ne peux pas le faire car la variable est immuable.
let mut x: i32 = 1337; let mut x_ref: &mut i32 = &mut x; // I've added mut before x_ref let mut z = 0; x_ref = &mut z; // Allowed!
Il y a trop d'instances de mut
ici autour x_ref
, n'est-ce pas ? Décrivons-les.
let mut x_ref
: je crée une variable mutable nommée x_ref
, ce qui signifie que je peux modifier sa valeur plus tard.
&mut i32
: je déclare que la variable contiendra une ou plusieurs références mutables à une valeur de type i32
.
&mut x
: j'emprunte (obtiens une référence à) la variable x
.
Ensuite, j'ai créé une variable nommée z
et lui ai attribué la valeur 0
. Par la suite, lorsque j'ai écrit x_ref = &mut z
, j'ai indiqué que je comprenais que x_ref
était une variable mutable qui ne pouvait contenir que des références à des valeurs i32
.
Puisque le type de z
est i32
, je peux attribuer son adresse à la variable x_ref
. Pour obtenir l'adresse de z
, j'ai utilisé la syntaxe &mut z
.
Jetez un oeil à =
dans la déclaration, cela peut paraître un peu évident, mais…
let mut x_ref = &mut x;
… Je le vois comme un diviseur (surtout si vous le faites pivoter de 90 degrés) qui divise l'instruction en deux sous-instructions : gauche et droite. Le côté gauche fournit des informations sur la variable elle-même, tandis que le côté droit nous renseigne sur la valeur .
Lorsque j'utilise l'opérateur de déréférencement *
pour modifier la valeur...
*x_ref = 100;
... Je ne change pas la valeur de la variable x_ref
. Au lieu de cela, je modifie la valeur à laquelle x_ref
fait référence.
J'utilisais fréquemment mut
auparavant. Et si j’en oublie certains ?
let i = 1; let j = 2; let mut k = &i;
Puis-je changer la valeur de i
ici ? En utilisant la technique du diviseur, il est assez simple de répondre. Je peux changer la valeur de k
(je vois mut
sur le côté gauche), mais la valeur (côté droit) est une référence immuable à i
(il n'y a pas mut
ici).
let i = 1; let j = 2; let mut k = &i; k = &j; // This is legal. *k = 3; // This is not.
Dans cet article, nous avons disséqué les nuances du mot-clé et des références mut
. N'oubliez pas qu'il existe une distinction entre une référence mutable et une variable mutable contenant une référence. Notre astuce ?
Utiliser le signe =
comme diviseur mental pour mieux comprendre les missions dans Rust. Cette simple visualisation peut dissiper de nombreuses confusions.