Rust

Any donation is very welcome
Fork me on GitHub

I. Les bases de la programmation en Rust

4. Variables

La première chose à savoir en Rust est que les variables sont toutes 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 !

Maintenant voyons comment fonctionnent les types en Rust. Ici, rien de nouveau, on a toujours des entiers, des flottants, des strings, etc... La seule différence viendra de leur syntaxe. Par exemple, pour déclarer un entier de 32 bits, vous ferez :

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

Sachez aussi que le compilateur de Rust utilise l'inférence de type. En gros, on n'est pas obligé de déclarer le type d'une variable, il peut généralement le déduire tout seul. Exemple :

Runlet i = 0; // donc c'est un entier visiblement
let max = 10i32;

if i < max { // max est un i32, donc le compilateur en déduit que i en est un aussi
    println!("i est inférieur à max !");
}

Donc pour résumer, voici une petite liste des différents types de base disponibles :

  • i8 : un entier signé de 8 bits
  • i16
  • i32
  • i64
  • u8 : un entier non-signé de 8 bits
  • u16
  • u32
  • u64
  • f32 : un nombre flottant de 32 bits
  • f64 : un nombre flottant de 64 bits
  • String
  • 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;

Il est temps de revenir sur les slices.

Les slices

Pour faire simple, une slice représente un morceau de tableau. Pour ceux qui auraient fait du C/C++, c'est tout simplement un pointeur et une taille. Exemple :

Runlet tab = &[0, 1, 2]; // tab est une slice contenant 0, 1 et 2

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

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

Runlet mut v: Vec<u8> = Vec::new();

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

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

Voilà qui conclut ce chapitre.