Rust - Fonctions
Les fonctions prévalent en Rust. On a déja vu la fonction majeure de Rust, la fonction main
, qqui est le point d'entrée des programmes. On a aussi vu le mot clé fn
qui nous permet de déclarer des fonctions.
Rust utiliste la snake case comme style conventionel pour les noms de variable et de fonction.
Voici un programme qui définit une fonction :
fn main() {
println!("Hello, world!");
autre_fonction();
}
fn autre_fonction() {
println!("Une autre fonction.");
}
On peut appeller une fonction en écrivant son nom avec des parenthèses après le nom de la fonction. Étant donné que autre_fonction
est définie dans le programme, il peut être appelé dans la fonction main
. On remarquera qu'on a définit la fonction autre_fonction
après la fonction main
. On aurait pu également la définir avant, ce qui n'aurait rien changé. Rust n'en prendra pas compte, il faut seulement que la fonction soit dans l'espace de nom adéquat pour pouvoir être appelé.*
Paramètres
Une fonction peut être définie avec des paramètres, qui sont des variables spéciales liées a la fonction.
Dans cette version de autre_fonction
, on ajoute un paramètre.
fn main() {
autre_fonction(5);
}
fn autre_fonction(x: i32) {
println!("La valeur de x est: {x}");
}
La déclaration de autre_fonction
possède un paramètre x
. Le type de x
est i32
. Quand on passe 5
a autre_fonction
, println!
remplace le {x}
par la valeur de x
.
Dans les signatures des fonctions, on est obligé de déclarer le type de chaque paramètres. C'est une décision délibérée qui a été prise dans le design de Rust : la nécessité de l'annotation de type dans la définition des fonctions veut dire que le compileur n'a presque jamais besoin que vous utilisiez les paramètres autre part pour deviner quel type vous utilisez. Il est capable également de vous donner des messages d'erreur plus utiles s'il sait quel type on utilise.
On peut définir plusieurs paramètres en les séparant par des virgules comme dans l'exemple ci dessous
fn main() {
afficher_mesure_avec_unitee(5, 'h');
}
fn afficher_mesure_avec_unitee(mesure: i32, unitee: char) {
println!("La mesure est: {mesure}{unitee}");
}
Déclarations et expressions
Les corps de fonctions sont faites d'une série de déclarations et se termine optionellement par une expression. Jusqu'ici, les fonctions qu'on a couvert n'ont pas inclut une expression finale, mais on a vu des expressions a l'intérieur de déclarations. Étant donné que le Rust est un langage basé sur des expressions, c'est une distinction importante a comprendre. Les autres langages n'ont pas ces distinctions donc il est important de la comprendre.
- Les déclarations sont des instructions qui font une actions et ne renvoient pas de valeurs.
- Les expressions s'évaluent a un résultat.
On a déja utilisé des déclarations et des expressions. Créer une variable et lui assigner une valeur avec let
est une déclaration.
La définition d'une fonction est aussi une déclaration.
Les déclarations de renvoient pas de valeurs. C'est pour cela qu'on peut pas assigner une déclaration en let
a une autre variable.
Les expressions s'évaluent a un résultat et sont la plupart du reste du code qu'on écrira en Rust. Considérons une opération mathématique comme 5+6
qui est une expression qui s'évalue a la valeur 11. Les expressions peuvent faire partie de déclarations. Appeler une fonction est une expression. Appeler une macro est une expression. Un nouveau champ est une expression, avec pour exemple :
fn main() {
let y = {
let x = 3;
x + 1
};
println!("La valeur de y est: {y}");
}
L'expression
let x = 3;
x + 1
est un block qui, dans ce cas, s'évalue a 4. Cette valeur est liéeé a y
comme partie de l'expression let
Remarquons que x+1
n'a pas de point-virgule a la fin, ce qui est différent de toutes les lignes jusqu'a présent. Les expressions n'ont pas de point-virgules finaux. Si on y ajoute un, cela va la transformer en déclaration, ce qui ne va pas retourner une valeur. Gardons cela a l'esprit pendant qu'on explore les valeurs renvoyés
Fonctions avec valeurs renvoyées
Les fonctions doivent renvoyer des valeur au code qui les appelle. On ne leur donne pas de nom, mais on doit déclarer après une flèche (->
). En Rust, la valeur renvotée est synonyme de la valeur de la dernière expression dans le bloc du corps d'une fonction. On peut renvoyer une valeur plus tot en utilisant le mot-clé return
avec une valeur, mais la plupart en renvoient une implicitement. En voici un exemple :
fn cinq() -> i32 {
5
}
fn main() {
let x = cinq();
println!("La valeur de x est: {x}");
}
let
dans la fonction, juste le nombre 5. C'est une fonction parfaitement valide en Rust. Notons que le type de la valeur renvoyée est spécifiée également, comme -> i32
Le 5 dans la fonction est la valeur renvoyée. Cela reviendrait a écrire
let x = 5;
Prenons un autre exemple :
fn main() {
let x = plus_un(5);
println!("La valeur de x est: {x}");
}
fn plus_un(x: i32) -> i32 {
x + 1
}
L'exécution de ce code afichera La valeur de x est 6
. Mais si on place un point-virgule a la fin de la ligne qui contient x+1
, ce qui la transforme en déclaration, cela nous crée une erreur
fn main() {
let x = plus_un(5);
println!("La valeur de x est: {x}");
}
fn plus_un(x: i32) -> i32 {
x + 1;
}
Compiler ce code nous donnera l'erreur suivante :
$ cargo run
Compiling functions v0.1.0 (file:///projects/functions)
error[E0308]: mismatched types
--> src/main.rs:7:24
|
7 | fn plus_un(x: i32) -> i32 {
| -------- ^^^ expected `i32`, found `()`
| |
| implicitly returns `()` as its body has no tail or `return` expression
8 | x + 1;
| - help: remove this semicolon to return this value
For more information about this error, try `rustc --explain E0308`.
error: could not compile `functions` due to previous error
Le message d'erreur principal, mismached types
nous révèle le problème centrale avec ce code. La définition de la fonction dit qu'elle renverra un i32
, mais les déclarations ne donnent pas de valeur, qui est exprimé par ()
, le type unité. Rien est donc retourné, ce qui est contredit par la définition de la fonction et qui donne une erreur. Dans cette sortie, Rust donne un pessage d'erreur pour aider a réparer cette erreur : il sugère de retirer le point-virgule, ce qui rectifie cette erreur.