Variables et mutabilité

RustRustBeginner
Pratiquer maintenant

This tutorial is from open-source community. Access the source code

💡 Ce tutoriel est traduit par l'IA à partir de la version anglaise. Pour voir la version originale, vous pouvez cliquer ici

Introduction

Bienvenue dans Variables et mutabilité. Ce laboratoire est une partie du Rust Book. Vous pouvez pratiquer vos compétences Rust dans LabEx.

Dans ce laboratoire, nous explorons le concept de mutabilité en Rust, en discutant de la manière dont les variables sont immuables par défaut et de la manière de les rendre mutables en utilisant le mot clé mut, et en mettant en évidence l'importance de l'immuabilité pour la sécurité et la concurrence tout en reconnaissant l'utilité de la mutabilité dans certaines situations.

Ceci est un Guided Lab, qui fournit des instructions étape par étape pour vous aider à apprendre et à pratiquer. Suivez attentivement les instructions pour compléter chaque étape et acquérir une expérience pratique. Les données historiques montrent que c'est un laboratoire de niveau débutant avec un taux de réussite de 87%. Il a reçu un taux d'avis positifs de 100% de la part des apprenants.

Variables et mutabilité

Comme mentionné dans "Stockage de valeurs avec des variables", par défaut, les variables sont immuables. C'est l'un des nombreux conseils que Rust vous donne pour écrire votre code de manière à profiter de la sécurité et de la facilité de concurrence que Rust offre. Cependant, vous avez toujours la possibilité de rendre vos variables mutables. Explorerons comment et pourquoi Rust vous encourage à privilégier l'immuabilité et pourquoi parfois vous voudrez peut-être vous en écarter.

Lorsqu'une variable est immutable, une fois qu'une valeur est liée à un nom, vous ne pouvez pas changer cette valeur. Pour illustrer cela, générez un nouveau projet appelé variables dans votre répertoire projet en utilisant cargo new variables.

Ensuite, dans votre nouveau répertoire variables, ouvrez src/main.rs et remplacez son code par le code suivant, qui ne compilera pas encore :

Nom de fichier : src/main.rs

fn main() {
    let x = 5;
    println!("The value of x is: {x}");
    x = 6;
    println!("The value of x is: {x}");
}

Enregistrez et exécutez le programme en utilisant cargo run. Vous devriez recevoir un message d'erreur concernant une erreur d'immuabilité, comme indiqué dans cette sortie :

$ cargo run
   Compiling variables v0.1.0 (file:///projects/variables)
error[E0384]: cannot assign twice to immutable variable `x`
 --> src/main.rs:4:5
  |
2 |     let x = 5;
  |         -
  |         |
  |         first assignment to `x`
  |         help: consider making this binding mutable: `mut x`
3 |     println!("The value of x is: {x}");
4 |     x = 6;
  |     ^^^^^ cannot assign twice to immutable variable

Cet exemple montre comment le compilateur vous aide à trouver des erreurs dans votre programme. Les erreurs du compilateur peuvent être frustrantes, mais en réalité, elles ne signifient que votre programme ne fait pas encore sûrement ce que vous voulez qu'il fasse ; elles ne signifient pas que vous n'êtes pas un bon programmeur! Les Rustaceans expérimentés reçoivent toujours des erreurs du compilateur.

Vous avez reçu le message d'erreur cannot assign twice to immutable variablex`car vous avez essayé d'affecter une deuxième valeur à la variable immutablex`.

Il est important que nous recevions des erreurs au moment de la compilation lorsqu'il s'agit d'essayer de changer une valeur qui est désignée comme immutable car cette situation précise peut entraîner des bogues. Si une partie de notre code fonctionne en supposant qu'une valeur ne changera jamais et qu'une autre partie de notre code change cette valeur, il est possible que la première partie du code ne fasse pas ce pour quoi elle a été conçue. La cause de ce type de bogue peut être difficile à repérer après coup, surtout lorsque la deuxième partie du code ne change la valeur que parfois. Le compilateur Rust garantit que lorsque vous déclarez qu'une valeur ne changera pas, elle ne changera vraiment pas, de sorte que vous n'avez pas à vous en occuper vous-même. Votre code est donc plus facile à comprendre.

Mais la mutabilité peut être très utile et peut rendre le code plus pratique à écrire. Bien que les variables soient immuables par défaut, vous pouvez les rendre mutables en ajoutant mut devant le nom de la variable, comme vous l'avez fait au chapitre 2. Ajouter mut indique également l'intention aux lecteurs futurs du code en montrant que d'autres parties du code modifieront la valeur de cette variable.

Par exemple, modifions src/main.rs comme suit :

Nom de fichier : src/main.rs

fn main() {
    let mut x = 5;
    println!("The value of x is: {x}");
    x = 6;
    println!("The value of x is: {x}");
}

Lorsque nous exécutons le programme maintenant, voici ce que nous obtenons :

$ cargo run
   Compiling variables v0.1.0 (file:///projects/variables)
    Finished dev [unoptimized + debuginfo] target(s) in 0.30s
     Running `target/debug/variables`
The value of x is: 5
The value of x is: 6

Nous sommes autorisés à changer la valeur liée à x de 5 à 6 lorsque mut est utilisé. En fin de compte, décider d'utiliser ou non la mutabilité vous appartient et dépend de ce que vous trouvez le plus clair dans cette situation particulière.

#Constantes

Comme les variables immuables, les constantes sont des valeurs qui sont liées à un nom et ne sont pas autorisées à changer, mais il existe quelques différences entre les constantes et les variables.

Tout d'abord, vous n'êtes pas autorisé à utiliser mut avec les constantes. Les constantes ne sont pas seulement immuables par défaut - elles sont toujours immuables. Vous déclarez les constantes en utilisant le mot clé const au lieu du mot clé let, et le type de la valeur doit être annoté. Nous aborderons les types et les annotations de type dans "Types de données", donc ne vous inquiétez pas des détails pour l'instant. Sachez seulement que vous devez toujours annoter le type.

Les constantes peuvent être déclarées dans n'importe quel contexte, y compris le contexte global, ce qui les rend utiles pour les valeurs dont de nombreuses parties du code ont besoin de savoir.

La dernière différence est que les constantes peuvent seulement être définies à une expression constante, pas au résultat d'une valeur qui ne pourrait être calculée qu'à l'exécution.

Voici un exemple de déclaration de constante :

const THREE_HOURS_IN_SECONDS: u32 = 60 * 60 * 3;

Le nom de la constante est THREE_HOURS_IN_SECONDS et sa valeur est définie au résultat de la multiplication de 60 (le nombre de secondes dans une minute) par 60 (le nombre de minutes dans une heure) par 3 (le nombre d'heures que nous voulons compter dans ce programme). La convention de nommage des constantes en Rust est d'utiliser toutes les majuscules avec des tirets du bas entre les mots. Le compilateur est capable d'évaluer un ensemble limité d'opérations à la compilation, ce qui nous permet de choisir d'écrire cette valeur d'une manière plus facile à comprendre et à vérifier, plutôt que de définir cette constante à la valeur 10 800. Consultez la section de la référence Rust sur l'évaluation des constantes à https://doc.rust-lang.org/reference/const_eval.html pour plus d'informations sur les opérations qui peuvent être utilisées lors de la déclaration des constantes.

Les constantes sont valides pour toute la durée de l'exécution d'un programme, dans le contexte dans lequel elles ont été déclarées. Cette propriété rend les constantes utiles pour les valeurs dans votre domaine d'application dont plusieurs parties du programme pourraient avoir besoin de savoir, comme le nombre maximal de points que n'importe quel joueur d'un jeu est autorisé à gagner, ou la vitesse de la lumière.

Donner un nom aux valeurs codées en dur utilisées tout au long de votre programme en tant que constantes est utile pour communiquer la signification de cette valeur aux futurs mainteneurs du code. Cela aide également à n'avoir qu'un seul endroit dans votre code où vous devriez modifier si la valeur codée en dur devait être mise à jour à l'avenir.

Ombre (Shadowing)

Comme vous l'avez vu dans le tutoriel du jeu de devinette au chapitre 2, vous pouvez déclarer une nouvelle variable avec le même nom qu'une variable précédente. Les Rustaceans disent que la première variable est ombragée par la seconde, ce qui signifie que la seconde variable est celle que le compilateur verra lorsque vous utiliserez le nom de la variable. En effet, la seconde variable obscurcit la première, prenant toutes les utilisations du nom de variable pour elle-même jusqu'à ce qu'elle soit elle-même ombragée ou que la portée se termine. Nous pouvons ombrager une variable en utilisant le même nom de variable et en répétant l'utilisation du mot clé let comme suit :

Nom de fichier : src/main.rs

fn main() {
    let x = 5;

    let x = x + 1;

    {
        let x = x * 2;
        println!("The value of x in the inner scope is: {x}");
    }

    println!("The value of x is: {x}");
}

Ce programme lie d'abord x à une valeur de 5. Ensuite, il crée une nouvelle variable x en répétant let x =, prenant la valeur initiale et ajoutant 1 de sorte que la valeur de x soit alors 6. Ensuite, à l'intérieur d'une portée interne créée avec les accolades, la troisième instruction let ombre également x et crée une nouvelle variable, multipliant la valeur précédente par 2 pour donner à x une valeur de 12. Lorsque cette portée est terminée, l'ombre interne se termine et x revient à être 6. Lorsque nous exécutons ce programme, il affichera ceci :

$ cargo run
   Compiling variables v0.1.0 (file:///projects/variables)
    Finished dev [unoptimized + debuginfo] target(s) in 0.31s
     Running `target/debug/variables`
The value of x in the inner scope is: 12
The value of x is: 6

L'ombre est différente de la marque d'une variable comme mut car nous obtiendrons une erreur de compilation si nous essayons accidentellement de réaffecter cette variable sans utiliser le mot clé let. En utilisant let, nous pouvons effectuer quelques transformations sur une valeur mais laisser la variable être immuable après que ces transformations ont été effectuées.

L'autre différence entre mut et l'ombre est que parce que nous créons effectivement une nouvelle variable lorsque nous utilisons à nouveau le mot clé let, nous pouvons changer le type de la valeur mais réutiliser le même nom. Par exemple, disons que notre programme demande à un utilisateur de montrer combien d'espaces ils veulent entre certains textes en saisissant des caractères d'espace, puis que nous voulons stocker cette entrée comme un nombre :

let spaces = "   ";
let spaces = spaces.len();

La première variable spaces est de type chaîne de caractères et la seconde variable spaces est de type nombre. L'ombre nous épargne donc de devoir trouver des noms différents, tels que spaces_str et spaces_num ; au lieu de cela, nous pouvons réutiliser le nom plus simple spaces. Cependant, si nous essayons d'utiliser mut pour cela, comme montré ici, nous obtiendrons une erreur de compilation :

let mut spaces = "   ";
spaces = spaces.len();

L'erreur indique que nous ne sommes pas autorisés à modifier le type d'une variable :

$ cargo run
   Compiling variables v0.1.0 (file:///projects/variables)
error[E0308]: mismatched types
 --> src/main.rs:3:14
  |
2 |     let mut spaces = "   ";
  |                      ----- expected due to this value
3 |     spaces = spaces.len();
  |              ^^^^^^^^^^^^ expected `&str`, found `usize`

Maintenant que nous avons exploré la façon dont les variables fonctionnent, regardons les différents types de données qu'elles peuvent avoir.

Sommaire

Félicitations! Vous avez terminé le laboratoire Variables et mutabilité. Vous pouvez pratiquer d'autres laboratoires dans LabEx pour améliorer vos compétences.