4. Les assignations▲
Rust assure l'immuabilité du type d'une variable grâce au typage statique. Lorsqu'une variable est déclarée elle peut être typée. Cependant, dans la plupart des cas, le compilateur sera capable d'inférer le type de la variable en se basant sur le contexte, atténuant sérieusement la lourdeur du typage.
Les valeurs (tels que les littéraux) peuvent être assignées à des variables en utilisant le mot-clé let
.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
fn
main() {
let
an_integer = 1
u32;
let
a_boolean = true
;
let
unit = ();
// Copie `an_integer` dans `copied_integer`.
let
copied_integer = an_integer;
println!
("An integer:
{:?}
"
, copied_integer); // un entier
println!
("A boolean:
{:?}
"
, a_boolean); // un booléen
println!
("Meet the unit value:
{:?}
"
, unit); // rien
// Le compilateur vous alertera lorsqu'il détecte une variable inutilisée;
// Vous pouvez faire taire ces avertissements en préfixant l'identificateur
// de la variable avec un underscore (i.e. _).
let
_unused_variable = 3
u32;
let
noisy_unused_variable = 2
u32;
// FIXME ^ Préfixez cet identificateur avec un underscore pour supprimer
// l'avertissement.
}
4-1. Mutabilité▲
L'assignation à une variable est immuable par défaut mais ceci peut être changé en utilisant le modificateur mut
.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
fn
main() {
let
_immutable_binding = 1
;
let
mut
mutable_binding = 1
;
println!
("Avant modification:
{}
"
, mutable_binding);
// Ok
mutable_binding += 1
;
println!
("Après modification:
{}
"
, mutable_binding);
// Erreur!
//_immutable_binding += 1;
// FIXME ^ Décommentez cette ligne pour voir le message d'erreur
}
4-2. Scope et shadowing▲
Les assignations possèdent un contexte dans lequel elles persisteront et qui sera représenté par un « bloc ». Un bloc est une suite d'instructions et de déclarations englobées par des accolades {}. Le shadowing est également permis.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
fn
main() {
// Cette assignation vit dans la fonction `main`.
let
long_lived_binding = 1
;
// Ceci est un bloc, il possède un contexte plus petit que celui de la fonction
// `main`.
{
// Cette assignation existe seulement dans ce bloc.
let
short_lived_binding = 2
;
println!
("inner short:
{}
"
, short_lived_binding);
// Cette assignation *masque* l'assignation du contexte supérieur (la fonction
// `main`).
let
long_lived_binding = 5_
f32;
println!
("inner long:
{}
"
, long_lived_binding);
}
// Fin du bloc.
// Erreur! `short_lived_binding` n'existe pas dans ce contexte.
// println!("outer short: {}", short_lived_binding);
// FIXME ^ Décommentez cette ligne pour voir l'erreur.
println!
("outer long:
{}
"
, long_lived_binding);
// Cette assignation *masque* également l'assignation précédente.
let
long_lived_binding = 'a'
;
println!
("outer long:
{}
"
, long_lived_binding);
}
4-3. Déclaration seule▲
Il est possible de déclarer une variable dans un premier temps, pour l'initialiser dans un second temps. Cependant, cette forme est rarement utilisée puisqu'elle peut conduire à l'utilisation de variables qui ne sont pas initialisées (et donc à faire des erreurs).
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
fn
main() {
// On déclare une variable.
let
a_binding;
{
let
x = 2
;
// On initialise la variable.
a_binding = x * x;
}
println!
("a binding:
{}
"
, a_binding);
let
another_binding;
// Erreur! Utilisation d'une variable non-initialisée.
// println!("another binding: {}", another_binding);
// FIXME ^ Décommentez cette ligne pour voir l'erreur.
another_binding = 1
;
println!
("another binding:
{}
"
, another_binding);
}
Comme l'utilisation d'une variable, qui n'a pas été initialisée au préalable, peut mener à des comportements imprévisibles à l'exécution, le compilateur vous interdit de les utiliser.