Les Options en Rust : des valeurs possiblement nulles
Dans cet article on va parler du type Option
de Rust.
C’est une des inventions du langage qui est vraiment très pratique.
Le type Option
est en réalité un enum qui prend la forme :
Si tu as oublié comment fonctionnent les enums tu peux aller voir mon article sur les enums 😉 .
Ici tu dois te demander “Mais d’où il sort ce T ?”.
En réalité T est ce qu’on appelle un type générique, on n’a pas encore vu ça, mais sache que cette syntaxe signifie simplement que T peut être n’importe quel type précisé par le développeur.
Donc si on écrit Option<u32>
Cela correspond à :
Bon d’accord, mais on n’est pas plus avancé là… :smile:
En fait ce type permet de régler un énorme problème qu’on a en programmation…
Dans tous les langages où on a un type null
les variables peuvent toujours être dans un des 2 états suivant : null ou non-null.
Petit problème : lorsqu’on essaye d’agir avec une variable null comme si elle n’était pas null, par exemple en faisant une addition, et bah forcément on a une erreur, et donc si on ne pense pas à vérifier explicitement que notre variable n’est pas null on va créer des erreurs.
Rust a résolu le problème en créant le type Option
dont les variantes sont :
None
, dans le cas ou notre variante n’a aucune valeurSome(T)
, qui est une variante avec une valeur non nommée de type T (qui peut être n’importe quel type précisé par le développeur)
Et donc si notre variante possède bien une valeur, elle n’est pas du même type que le type en question et donc on ne peut pas les additionner directement et il va falloir passer par une vérification obligatoire pour récupérer la valeur.
Bon vu que c’est assez abstrait on va faire un exemple :
Comme je te le disais on peut pas ajouter directement un type Option<u8>
avec un type u8
.
Pour le faire il faut d’abord extraire la valeur de la variante qui est contenue dans Some(14)
dans cet exemple.
C’est ce qu’on va voir juste après avec la méthode unwrap().
En faisant ça Rust nous force à vérifier que la valeur n’est pas null et ainsi il évite tous les problèmes qu’on pourrait rencontrer dans les autres langages ou on essaye d’ajouter une valeur null avec une valeur non null.
Les méthodes des Options
Le type Option nous donne accès à plusieurs méthodes très pratique, toutes les méthodes qui vont suivre s’utilisent sur n’importe quelle variante d’un type Option.
unwrap()
La méthode unwrap() nous permet d’extraire la valeur contenue dans la variante Some
.
En utilisant unwrap() on a pu extraire la valeur 14 de b.
Mais que se passe t il si b vaut None ?
Tu vois qu’on ne peut pas utiliser unwrap()
sur une variante None
, car il n’y a rien à extraire.
La grosse différence avec les autres langages où il y a un type null, c’est qu’ici l’erreur se fait au moment de l’extraction et pas au moment de l’addition.
Cette architecture du type option, va nous permettre de vérifier certaines choses avant de continuer et c’est ce qu’on va voir avec les méthodes suivantes.
is_none()
La méthode is_none()
nous renvoie true
si l’option est None
et nous renvoie false
si l’option est Some
is_some()
La méthode is_some()
nous renvoie true
si l’option est Some
et nous renvoie false
si l’option est None
unwrap_or()
La méthode unwrap_or
nous permet :
- Si l’option est
Some
de retourner la valeur dans leSome
- Si l’option est
None
de retourner la valeur fournie en paramètre
Cela nous permet de donner une valeur par défaut si notre option est None.
Des fonctions avec des paramètres optionnels
Comme on l’a vu dans l’article sur les fonctions, on ne peut pas créer une fonction avec des paramètres optionnels en Rust.
Si une fonction a 3 paramètres on doit spécifier ces 3 paramètres à chaque appel de la fonction.
Pourtant, il y a bien des cas ou certains paramètres n’ont pas toujours une valeur dans nos fonctions !
Les options vont nous permettre de spécifier des paramètres optionnels.
Ici la fonction add
prend 3 paramètres, dont le 3ᵉ a une valeur “optionnelle”, d’où son type Option<u32>
.
Il devra toujours être spécifié, mais son type Option
permet de lui donner une valeur ou non.
Ensuite dans la fonction on vérifie si c
est None
, si c’est le cas on retourne que a+b sinon on retourne a+b+c.unwrap() car pour ajouter c
il faut extraire sa valeur avec unwrap