Loading prj_rust_training_2...
&selfpour la consultation ou
&mut selfpour la modification de la structure concernée).
rustup doc --std 'std::vec::Vec') Pour connaître la longueur d'un vector (ou un d'autre ensemble de données) il suffit de lui appliquer la fonction .len().
rustup doc --std 'std::vec::Vec') Une donnée de type T optionnelle est représentée par le type Option<T>.
.sum::<T>()(où T représente le type de la somme attendue) accolé à l'itérateur qui fournit les éléments.
&selfpour la consultation ou
&mut selfpour la modification de la structure concernée).
rustup doc --std 'std::vec::Vec') Pour connaître la longueur d'un vector (ou un d'autre ensemble de données) il suffit de lui appliquer la fonction .len().
rustup doc --std 'std::vec::Vec') Une donnée de type T optionnelle est représentée par le type Option<T>.
.min_by_key()(avec une closure exprimant le passage de l'élément visité à la valeur qui sert à la comparaison) accolé à l'itérateur qui fournit les éléments.
.min()accolé à l'itérateur qui fournit les éléments.
//~~~~ First variant ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/// A mark obtained in a course. #[derive(Debug, Clone)] pub struct Mark { pub course: String, pub value: f64, }
impl Mark { /// Builds a mark from its provided properties. pub fn new( course: String, value: f64, ) -> Self { Self { course, value } } }
/// A student memorizing her/his name and her/his marks. #[derive(Debug, Clone)] pub struct Student { name: String, marks: Vec<Mark>, }
impl Student { /// Builds a student from her/his name (without any mark yet). pub fn new(name: String) -> Self { Self { name, marks: Vec::new(), } }
/// Accesses (read-only) this student's name. pub fn name(&self) -> &str { self.name.as_str() }
/// Accesses (read-only) this student's marks. pub fn marks(&self) -> &[Mark] { self.marks.as_slice() }
/// Sets or changes a mark for this student. /// /// If a mark already exists for this course, /// then its value is replaced by the newly provided one. pub fn set_mark( &mut self, mark: Mark, ) { if false { // one possible solution (explicit loop) for m in self.marks.iter_mut() { if m.course == mark.course { m.value = mark.value; return; } } self.marks.push(mark); } else { // a more concise solution (functional style) match self.marks.iter_mut().find(|m| m.course == mark.course) { Some(m) => m.value = mark.value, None => self.marks.push(mark), } } }
/// Accesses this student's mark for the specified course. /// /// If this student has no mark in this course, then None is returned. pub fn get_mark( &self, course: &str, ) -> Option<&Mark> { if false { // one possible solution (explicit loop) for mark in self.marks.iter() { if mark.course == course { return Some(mark); } } None } else { // a more concise solution (functional style) self.marks.iter().find(|mark| mark.course == course) } }
/// Computes the average of this student's marks. /// /// If this student has no mark, then None is returned. pub fn average_mark(&self) -> Option<f64> { if false { // one possible solution (explicit loop) if self.marks.is_empty() { None } else { let mut accum = 0.0; for mark in self.marks.iter() { accum += mark.value; } Some(accum / self.marks.len() as f64) } } else { // a more concise solution (functional style) if self.marks.is_empty() { None } else { Some( self.marks.iter().map(|mark| mark.value).sum::<f64>() / self.marks.len() as f64, ) } } } }
/// Computes the average mark of a specific course for many students. /// /// If no student has a mark for this course, then None is returned. pub fn average_for_course( students: &[Student], course: &str, ) -> Option<f64> { if false { // one possible solution (explicit loop) let mut accum = 0.0; let mut count = 0; for student in students.iter() { if let Some(mark) = student.get_mark(course) { accum += mark.value; count += 1; } } if count == 0 { None } else { Some(accum / count as f64) } } else { // a more concise solution (functional style) let (accum, count) = students .iter() .filter_map(|student| student.get_mark(course)) .map(|mark| mark.value) .fold((0.0, 0), |(accum, count), value| { (accum + value, count + 1) }); if count == 0 { None } else { Some(accum / count as f64) } } }
//~~~~ Second variant ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/// A runner with its race time. #[derive(Debug, Clone)] pub struct Runner { pub name: String, pub seconds: i32, }
impl Runner { /// Builds a runner from its provided properties. pub fn new( name: String, seconds: i32, ) -> Self { Self { name, seconds } } }
/// A race memorizing its city and its runners. #[derive(Debug, Clone)] pub struct Race { city: String, runners: Vec<Runner>, }
impl Race { /// Builds a race from its city (without any runner yet). pub fn new(city: String) -> Self { Self { city, runners: Vec::new(), } }
/// Accesses (read-only) the city of this race. pub fn city(&self) -> &str { self.city.as_str() }
/// Accesses (read-only) the runners of this race. pub fn runners(&self) -> &[Runner] { self.runners.as_slice() }
/// Sets or changes a runner for this race. /// /// If a runner with the same name already exists, /// then its race time is replaced by the newly provided one. pub fn set_runner( &mut self, runner: Runner, ) { if false { // one possible solution (explicit loop) for r in self.runners.iter_mut() { if r.name == runner.name { r.seconds = runner.seconds; return; } } self.runners.push(runner); } else { // a more concise solution (functional style) match self.runners.iter_mut().find(|r| r.name == runner.name) { Some(r) => r.seconds = runner.seconds, None => self.runners.push(runner), } } }
/// Accesses the runner with the specified name in this race. /// /// If the name is not found in this race, then None is returned. pub fn get_runner( &self, name: &str, ) -> Option<&Runner> { if false { // one possible solution (explicit loop) for runner in self.runners.iter() { if runner.name == name { return Some(runner); } } None } else { // a more concise solution (functional style) self.runners.iter().find(|runner| runner.name == name) } }
/// Determines the runner with the best time in this race. /// /// If this race has no runner, then None is returned. pub fn best_runner(&self) -> Option<&Runner> { if false { // one possible solution (explicit loop) let mut best: Option<&Runner> = None; for runner in self.runners.iter() { let update = match best { Some(b) => runner.seconds < b.seconds, None => true, }; if update { best = Some(runner); } } best } else { // a more concise solution (functional style) self.runners.iter().min_by_key(|runner| runner.seconds) } } }
/// Determines the best race time for a runner amongst many races. /// /// If this runner is not involved in any race, then None is returned. pub fn best_time_for_runner( races: &[Race], name: &str, ) -> Option<i32> { if false { // one possible solution (explicit loop) let mut best = None; for race in races.iter() { if let Some(runner) = race.get_runner(name) { let update = match best { Some(b) => runner.seconds < b, None => true, }; if update { best = Some(runner.seconds); } } } best } else { // a more concise solution (functional style) races .iter() .filter_map(|race| race.get_runner(name)) .map(|runner| runner.seconds) .min() } }
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
fn main() { //~~~~ First variant ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
use training_2::{average_for_course, Mark, Student};
let mut alice = Student::new("Alice".to_owned()); if alice.get_mark("Maths").is_none() { println!("no Maths yet for {}", alice.name()); } alice.set_mark(Mark::new("Maths".to_owned(), 12.0)); alice.set_mark(Mark::new("Maths".to_owned(), 14.0)); if let Some(mark) = alice.get_mark("Maths") { println!("{} got {} in {}", alice.name(), mark.value, mark.course); } alice.set_mark(Mark::new("Physics".to_owned(), 16.0)); alice.set_mark(Mark::new("English".to_owned(), 18.0));
let mut bob = Student::new("Bob".to_owned()); bob.set_mark(Mark::new("Physics".to_owned(), 12.0)); bob.set_mark(Mark::new("English".to_owned(), 8.0));
let charles = Student::new("Charles".to_owned());
let students = [alice, bob, charles]; for student in students.iter() { if let Some(avg) = student.average_mark() { println!("{:?} got {} with:", student.name(), avg); for mark in student.marks().iter() { println!("• {} in {}", mark.value, mark.course); } } else { println!("{:?} did not participate to anything", student.name()); } }
for course in ["Maths", "Physics", "English", "Italian"] { if let Some(avg) = average_for_course(students.as_slice(), course) { println!("average for {:?} is {}", course, avg); } else { println!("no one took {:?}", course); } }
//~~~~ Second variant ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
use training_2::{best_time_for_runner, Race, Runner};
let mut brest = Race::new("Brest".to_owned()); if brest.get_runner("Alice").is_none() { println!("Alice did not run yet in {}", brest.city()); } brest.set_runner(Runner::new("Alice".to_owned(), 2430)); brest.set_runner(Runner::new("Alice".to_owned(), 2385)); if let Some(runner) = brest.get_runner("Alice") { println!( "{} ran in {} seconds in {}", runner.name, runner.seconds, brest.city() ); } brest.set_runner(Runner::new("Bob".to_owned(), 2505)); brest.set_runner(Runner::new("Charles".to_owned(), 2610));
let mut nantes = Race::new("Nantes".to_owned()); nantes.set_runner(Runner::new("Bob".to_owned(), 2475)); nantes.set_runner(Runner::new("Charles".to_owned(), 2655));
let angers = Race::new("Angers".to_owned());
let races = [brest, nantes, angers]; for race in races.iter() { if let Some(runner) = race.best_runner() { println!("{:?} won in {:?}", runner.name, race.city()); for runner in race.runners().iter() { println!("• {:?} in {} seconds", runner.name, runner.seconds); } } else { println!("no one ran in {:?}", race.city()); } }
for runner in ["Alice", "Bob", "Charles", "Damian"] { if let Some(seconds) = best_time_for_runner(races.as_slice(), runner) { println!("best time for {:?} is {} seconds", runner, seconds); } else { println!("{:?} did not participate in any race", runner); } } }
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//~~~~ First variant ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#[test] fn students() { use training_2::{average_for_course, Mark, Student};
let mut alice = Student::new("Alice".to_owned()); assert_eq!(alice.name(), "Alice"); assert!(alice.marks().is_empty()); assert!(alice.get_mark("Maths").is_none()); alice.set_mark(Mark::new("Maths".to_owned(), 12.0)); alice.set_mark(Mark::new("Maths".to_owned(), 14.0)); assert_eq!(alice.get_mark("Maths").unwrap().value, 14.0); alice.set_mark(Mark::new("Physics".to_owned(), 16.0)); alice.set_mark(Mark::new("English".to_owned(), 18.0)); assert_eq!(alice.marks().len(), 3); assert_eq!(alice.average_mark().unwrap(), 16.0);
let mut bob = Student::new("Bob".to_owned()); bob.set_mark(Mark::new("Physics".to_owned(), 12.0)); bob.set_mark(Mark::new("English".to_owned(), 8.0)); assert_eq!(bob.marks().len(), 2); assert_eq!(bob.average_mark().unwrap(), 10.0);
let charles = Student::new("Charles".to_owned()); assert!(charles.marks().is_empty()); assert!(charles.average_mark().is_none());
let students = [alice, bob, charles]; assert_eq!( average_for_course(students.as_slice(), "Maths").unwrap(), 14.0 ); assert_eq!( average_for_course(students.as_slice(), "Physics").unwrap(), 14.0 ); assert_eq!( average_for_course(students.as_slice(), "English").unwrap(), 13.0 ); assert!(average_for_course(students.as_slice(), "Italian").is_none()); }
//~~~~ Second variant ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#[test] fn races() { use training_2::{best_time_for_runner, Race, Runner};
let mut brest = Race::new("Brest".to_owned()); assert_eq!(brest.city(), "Brest"); assert!(brest.runners().is_empty()); assert!(brest.get_runner("Alice").is_none()); brest.set_runner(Runner::new("Alice".to_owned(), 2430)); brest.set_runner(Runner::new("Alice".to_owned(), 2385)); assert_eq!(brest.get_runner("Alice").unwrap().seconds, 2385); brest.set_runner(Runner::new("Bob".to_owned(), 2505)); brest.set_runner(Runner::new("Charles".to_owned(), 2610)); assert_eq!(brest.runners().len(), 3); assert_eq!(brest.best_runner().unwrap().seconds, 2385);
let mut nantes = Race::new("Nantes".to_owned()); nantes.set_runner(Runner::new("Bob".to_owned(), 2475)); nantes.set_runner(Runner::new("Charles".to_owned(), 2655)); assert_eq!(nantes.runners().len(), 2); assert_eq!(nantes.best_runner().unwrap().seconds, 2475);
let angers = Race::new("Angers".to_owned()); assert!(angers.runners().is_empty()); assert!(angers.best_runner().is_none());
let races = [brest, nantes, angers]; assert_eq!( best_time_for_runner(races.as_slice(), "Alice").unwrap(), 2385 ); assert_eq!(best_time_for_runner(races.as_slice(), "Bob").unwrap(), 2475); assert_eq!( best_time_for_runner(races.as_slice(), "Charles").unwrap(), 2610 ); assert!(best_time_for_runner(races.as_slice(), "Damian").is_none()); }
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~