I. Les bases de la programmation en Rust
6. Les fonctions
Jusqu'à présent, nous n'utilisions qu'une seule fonction : main. Pour le moment c'est amplement suffisant, mais quand vous voudrez faire des programmes plus gros, ça deviendra vite ingérable. Je vais donc vous montrer comment créer des fonctions en Rust.
Commençons avec un exemple :
Runfn addition(nb1: i32, nb2: i32) -> i32
Ceci est donc une fonction appelée addition qui prend 2 arguments de type i32
en paramètre et retourne un i32
. Rien de très différent de ce que vous connaissez déjà donc.
Si vous souhaitez déclarer une fonction qui ne retourne rien (parce qu'elle ne fait qu'afficher du texte par exemple), vous pouvez la déclarer des façons suivantes :
Runfn fait_quelque_chose() {
println!("Je fais quelque chose !");
}
// ou bien :
fn fait_quelque_chose() -> () {
println!("Je fais quelque chose !");
}
Expliquons rapidement ce qu'est ce () : c'est un tuple vide. tuple est une structure de donnée qui a un nombre d'élements définis et dont les types peuvent différer. Ils sont utiles si l'on souhaite retourner plusieurs valeurs d'un coup :
Runfn entier_et_float() -> (usize, f32) {
(12, 0.1)
}
fn main() {
let tuple = entier_et_float();
// On accède aux champs avec leur position dans le tuple.
println!("entier : {}, float : {}", tuple.0, tuple.1);
}
Pour en revenir au tuple vide, son équivalent le plus proche en C/C++ est le type void (et non pas la valeur NULL). Prenons un exemple :
Runfn main() {
println!("1 + 2 = {}", addition(1, 2));
}
fn addition(nb1: i32, nb2: i32) -> i32 {
return nb1 + nb2;
}
Ce qui affiche :
1 + 2 = 3
Le mot-clé return retourne l'expression qui le suit. Donc ici, le résultat de l'addition nb1 + nb2
. À noter qu'il est aussi possible de se passer de return si c'est la dernière expression de la fonction. Par exemple on pourrait réécrire la fonction addition
de cette façon :
Runfn addition(nb1: i32, nb2: i32) -> i32 {
nb1 + nb2
}
Par défaut, tout est expression en Rust, le point-virgule permettant simplement de marquer la fin de l'expression courante.
Ne vous inquiétez pas si vous ne comprenez pas tout parfaitement, nous verrons les expressions dans le chapitre suivant. Un autre exemple pour illustrer cette différence :
Runfn get_bigger(nb1: i32, nb2: i32) -> i32 {
if nb1 > nb2 {
return nb1;
}
nb2
}
Cette façon de faire n'est cependant pas recommandée en Rust, il aurait mieux valu écrire :
Runfn get_bigger(nb1: i32, nb2: i32) -> i32 {
if nb1 > nb2 {
nb1
} else {
nb2
}
}
Une autre différence que certains d'entre vous auront peut-être noté (surtout ceux ayant déjà codé en C/C++) : je n'ai pas "déclaré" ma fonction addition et pourtant la fonction main l'a trouvé sans problème. Sachez juste que les déclarations de fonctions ne sont pas nécessaires en Rust (contrairement au C ou au C++ qui ont besoin de fichiers "header" par exemple).
Voilà pour les fonctions, rien de bien nouveau par rapport aux autres langages que vous pourriez déjà connaître.
Il reste cependant un dernier point à éclaircir : println! et tous les appels ayant un '!' ne sont pas des fonctions, ce sont des macros.
Si vous pensez qu'elles ont quelque chose à voir avec celles que l'on peut trouver en C ou en C++, détrompez-vous ! Elles sont l'une des plus grandes forces de Rust, elles sont aussi très complètes et permettent d'étendre les possibilités du langage. Par-contre, elles sont très complexes et seront le sujet d'un autre chapitre.
Pour le moment, sachez juste que :
Runfonction!(); // c'est une macro
fonction(); // c'est une fonction