#11 Option et Result
Option<T>, Result<T,E>, ?
Le type Option
En Rust, il n'y a pas de valeur null. À la place, on utilise le type Option<T> pour représenter une valeur qui peut être présente ou absente. C'est un enum avec deux variantes :
enum Option<T> {
Some(T), // une valeur est présente
None, // aucune valeur
}Option est si courant qu'il est importé automatiquement : vous pouvez utiliser Some et None directement.
fn trouver_utilisateur(id: u32) -> Option<String> {
if id == 1 {
Some(String::from("Alice"))
} else {
None
}
}
fn main() {
let user = trouver_utilisateur(1);
println!("{:?}", user); // Some("Alice")
let inconnu = trouver_utilisateur(42);
println!("{:?}", inconnu); // None
}Travailler avec Option
Plusieurs méthodes permettent d'extraire ou de transformer la valeur contenue dans un Option.
unwrap et expect
unwrap() extrait la valeur si elle existe, mais panique si c'est None. Préférez expect() qui affiche un message d'erreur personnalisé.
let valeur: Option<i32> = Some(42);
let x = valeur.unwrap(); // 42
let y = valeur.expect("oups"); // 42
let vide: Option<i32> = None;
// vide.unwrap(); // PANIC !map et and_then
map applique une fonction à la valeur interne sans la déballer manuellement. and_then (aussi appelé flatmap) est utile quand la fonction retourne elle-même un Option.
let nom: Option<String> = Some(String::from("Alice"));
// map : transformer la valeur interne
let longueur: Option<usize> = nom.map(|n| n.len());
println!("{:?}", longueur); // Some(5)
// and_then : chaîner des Option
fn premiere_lettre(s: String) -> Option<char> {
s.chars().next()
}
let lettre = Some(String::from("Rust")).and_then(premiere_lettre);
println!("{:?}", lettre); // Some('R')Le type Result
Result<T, E> est utilisé quand une opération peut échouer. Contrairement à Option, il fournit des informations sur pourquoi l'opération a échoué.
enum Result<T, E> {
Ok(T), // succès avec une valeur
Err(E), // erreur avec des détails
}use std::fs;
fn lire_fichier(chemin: &str) -> Result<String, std::io::Error> {
fs::read_to_string(chemin)
}
fn main() {
match lire_fichier("hello.txt") {
Ok(contenu) => println!("Le fichier contient : {}", contenu),
Err(e) => println!("Erreur : {}", e),
}
}L'opérateur ?
L'opérateur ? est un raccourci élégant : il extrait la valeur si c'est Ok (ou Some), et retourne immédiatement l'erreur si c'est Err (ou None).
use std::fs;
use std::io;
fn lire_et_compter(chemin: &str) -> Result<usize, io::Error> {
let contenu = fs::read_to_string(chemin)?; // retourne Err si échec
Ok(contenu.len())
}
fn main() {
match lire_et_compter("hello.txt") {
Ok(n) => println!("Le fichier fait {} octets", n),
Err(e) => println!("Erreur : {}", e),
}
}Convertir entre Option et Result
Vous pouvez convertir un Option en Result avecok_or, et un Result en Option avecok().
// Option -> Result
let opt: Option<i32> = Some(42);
let res: Result<i32, &str> = opt.ok_or("valeur absente");
println!("{:?}", res); // Ok(42)
let vide: Option<i32> = None;
let err: Result<i32, &str> = vide.ok_or("valeur absente");
println!("{:?}", err); // Err("valeur absente")
// Result -> Option
let res: Result<i32, &str> = Ok(10);
let opt: Option<i32> = res.ok();
println!("{:?}", opt); // Some(10)À vous de jouer
Essayez les commandes ci-dessous pour compiler et exécuter le programme :