====== Trouver le jour correspondant à une date ====== La récupération de la date venant d'une chaîne de texte est un peu fastidieuse mais montre un élément important de la programmation Rust : La gestion des erreurs. Dans beaucoup de langages, certaines situations lèvent une erreur et on peut être amenés à capter cette erreur avec une structure ''try ... except ...''. En Rust on préfère prévoir nos fonctions pour qu'elles renvoient un type ''Result'' qui est soit ''Ok'' et dans ce cas contient la valeur désirée, soit ''Err'' pour une erreur. Dans le cas présent, on envisage que la date fournie n'ait pas le bon format. Le retour de la fonction ''Date::from_str'' peut donc être une erreur. C'est pourquoi on envisage l'alternative : soit c'est ''Ok'' et on continue, soit c'est ''Err'' et on arrête. ''panic!'' permet d'interrompre l'exécution en vidant proprement la mémoire. use std::str::FromStr; // Ce trait permet d'implémenter la conversion from_str pour notre date use std::env; // pour récupérer les arguments de la ligne de commande const MOIS:[usize;12] = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]; const JOURS:[&str;7] = ["samedi", "dimanche", "lundi", "mardi", "mercredi", "jeudi", "vendredi"]; const AREF:usize = 2000; // année de référence struct Date { day: usize, month: usize, year: usize, } impl FromStr for Date { type Err = std::num::ParseIntError; // Parse un format JJ/MM/AAAA fn from_str(str_date: &str) -> Result { let day: usize = usize::from_str(&str_date[0..2])?; let month: usize = usize::from_str(&str_date[3..5])?; let year: usize = usize::from_str(&str_date[6..10])?; Ok(Date { day, month, year }) } } fn is_bissextile(annee: usize) -> bool { if annee % 1000 == 0 { true } else if annee % 100 == 0 { false } else if annee % 4 == 0 { true } else { false } } fn days_in_month(month: usize, annee:usize) -> usize { let n = MOIS[month - 1]; if (month == 2) && is_bissextile(annee) { n + 1 } else { n } } fn days_in_year(annee:usize) -> usize { if is_bissextile(annee) { 366 } else { 365 } } fn jours_finir_annee(jour: usize, mois: usize, annee:usize) -> usize { // renvoie le nombres de jours pour une certaines dates pour atteindre // le 1er janvier de l'année d'après let mut days:usize = days_in_month(mois, annee) - (jour-1); for m in (mois+1)..=12 { days += days_in_month(m, annee); } days } fn jours_depuis_debut(jour: usize, mois: usize, annee:usize) -> usize { // renvoie le nombres de jours pour atteindre une certaine date // depuis le 1e janvier de cette même année let mut days:usize = jour-1; for m in 1..mois { days += days_in_month(m, annee); } days } fn nombre_jours(jour: usize, mois: usize, annee:usize) -> usize { if annee >= AREF { let mut days = jours_depuis_debut(jour, mois, annee); for a in AREF..annee { days += days_in_year(a); } days % 7 } else { let mut days = jours_finir_annee(jour, mois, annee); for a in (annee+1)..AREF { days += days_in_year(a); } 7 - (days % 7) } } fn main() { // lecture des arguments donnés en ligne de commande let args: Vec = env::args().collect(); if args.len() < 2 { panic!("Entrez une date au format JJ/MM/AAAA."); } let date_str = &args[1]; let date = match Date::from_str(date_str) { Ok(d) => d, Err(_) => panic!("Entrez une date au format JJ/MM/AAAA."), }; let delta = nombre_jours(date.day, date.month, date.year); println!("Le {} était un {}.", date_str, JOURS[delta]); }