Acheter version papier

Rust

Fork me on GitHub

I. Les bases de la programmation en Rust

4. Variables

La première chose à savoir en Rust est que toutes les variables sont constantes par défaut. Exemple :

Runlet i = 0;

i = 2; // Erreur !

Pour déclarer une variable mutable, il faut utiliser le mot-clé mut :

Runlet mut i = 0;

i = 2; // Ok !

Les types

Voyons maintenant comment fonctionnent les types en Rust. Ici, rien de nouveau par-rapport à ce que vous avez pu voir dans d'autres langages, on a toujours des entiers, des flottants, des strings, etc. La seule différence viendra surtout de leur nommage. Par exemple, pour déclarer un entier de 32 bits, vous écrirez :

Runlet i: i32 = 0;
// ou :
let i = 0i32;

Vous devez également savoir que le compilateur de Rust utilise l'inférence de type. Cela signifie qu'il peut déduire le type d'une variable en fonction de sa valeur. Nous ne sommes donc pas obligés de déclarer le type d'une variable. Exemple :

Run// On se met dans la peau de rustc :
// 0 est un entier donc i est un entier
let i = 0;
// 10 est un i32 alors max est un i32
let max = 10i32;

// < est capable de comparer deux nombres alors comme on sait que :
// max est un i32, donc le compilateur en déduit que i en est un aussi
if i < max {
    println!("i est inférieur à max !");
}

Voici une liste des différents types de base (aussi appelés "primitifs") disponibles :

  • i8 : un entier signé de 8 bits
  • i16 : un entier signé de 16 bits
  • i32 : un entier signé de 32 bits
  • i64 : un entier signé de 64 bits
  • i128 : un entier signé de 128 bits
  • u8 : un entier non-signé de 8 bits
  • u16 : un entier non-signé de 16 bits
  • u32 : un entier non-signé de 32 bits
  • u64 : un entier non-signé de 64 bits
  • u128 : un entier non-signé de 128 bits
  • f32 : un nombre flottant de 32 bits
  • f64 : un nombre flottant de 64 bits
  • str (on va y revenir plus loin dans ce chapitre)
  • slice (on va y revenir plus loin dans ce chapitre)

Sachez cependant que les types isize et usize existent aussi et sont l'équivalent de intptr_t et de uintptr_t en C/C++. En gros, sur un système 32 bits, ils feront respectivement 32 bits tandis qu'ils feront 64 bits sur un système 64 bits.

Dernier petit point à aborder : il est courant de croiser ce genre de code en C/C++/Java/etc... :

Runi++;
++i;

Cette syntaxe est invalide en Rust, il vous faudra donc utiliser :

Runi += 1;

Autre détail qui peut avoir son importance : si on fait commencer le nom d'une variable par un '_', nous n'aurons pas de warning du compilateur si elle est inutilisée. Ça a son utilité dans certains cas, bien que cela reste assez restreint. Exemple :

Runlet _i = 0;

Les tableaux

On peut déclarer un tableau de cette façon :

Runlet tab = [0, 1, 2];

On ne peut pas modifier la taille d'un tableau, on peut seulement modifier son contenu. Si vous souhaitez avoir un tableau dont la taille peut être modifiée, il faudra utiliser le type Vec (prononcer "vecteur") :

Run// Un vecteur vide.
let mut v = Vec::new();

// On ajoute les valeurs 2, 1 et 0.
v.push(2);
v.push(1);
v.push(0);

// Ça affichera "[2, 1, 0]".
println!("{:?}", v);

Il est maintenant temps de revenir sur les slices.

Les slices

Pour faire simple, une slice représente un morceau de mémoire ainsi que le nombre d'éléments qu'elle contient. Contrairement aux tableaux, leur taille n'a pas besoin d'être connue au moment de la compilation, ce qui les rend beaucoup plus facile à manipuler. Cela deviendra plus évident quand on abordera les fonctions. Une slice est créée quand on utilise & devant un tableau. Exemples :

Run// tab est une slice contenant 0, 1 et 2.
let tab = &[0, 1, 2];
// Ça affichera "[0, 1, 2]".
println!("{:?}", tab);

// On crée une slice commençant à partir du 2e élément de tab.
let s = &tab[1..];
// Ça affichera "[1, 2]".
println!("{:?}", s);

De la même façon qu'il est possible d'obtenir une slice à partir d'un tableau ou d'une slice, on peut en obtenir à partir des Vecs :

Runlet mut v = Vec::new();

v.push(0);
v.push(1);
v.push(2);

// Ça affichera "[0, 1, 2]".
println!("{:?}", v);
let s = &v[1..];

// Ça affichera "[1, 2]".
println!("{:?}", s);

Les types contenant des tableaux ont toujours une slice associée. Par-exemple, String a &str, OsString a &OsStr, etc...