La généricité et des types composés

Ces exercices portent sur les types génériques, les traits, les tuples et les attributs #[derive]. Faites-les dans l'ordre.

Maximum générique

Écrire une fonction qui renvoie le plus grand de deux éléments, quel que soit leur type - du moment qu'on peut les comparer.

  • Objectif : paramètre générique <T>, contrainte T: PartialOrd.
  • Signature suggérée : fn maximum<T: PartialOrd>(a: T, b: T) -> T.
  • Cas de test : maximum(3, 8) -> 8, maximum(2.5, 1.0) -> 2.5, maximum("abc", "abd") -> "abd".

Paire générique

Définir struct Paire<T> { premier: T, second: T } et une fonction qui renvoie une nouvelle paire avec les deux champs échangés.

  • Objectif : struct générique, fonction (ou méthode) générique.
  • Signature suggérée : fn echanger<T>(p: Paire<T>) -> Paire<T>.
  • Cas de test : echanger(Paire { premier: 1, second: 2 }) -> Paire { premier: 2, second: 1 }.

Trait Aire

Définir trait Aire { fn aire(&self) -> f64; } et l'implémenter pour struct Cercle { rayon: f64 } et struct Carre { cote: f64 }.

  • Objectif : définition d'un trait, impl Trait for Type.
  • Signature suggérée : trait Aire { fn aire(&self) -> f64; }.
  • Cas de test : Carre { cote: 3.0 }.aire() -> 9.0, Cercle { rayon: 2.0 }.aire() -> environ 12.566.

Trait avec méthode par défaut

Définir trait Decrire avec une méthode nom(&self) -> String (obligatoire) et une méthode decrire(&self) -> String par défaut qui renvoie format!("Ceci est {}", self.nom()). Implémenter le trait pour un premier type en ne fournissant que nom, puis pour un second type en redéfinissant aussi decrire.

  • Objectif : méthode par défaut d'un trait, redéfinition.
  • Signature suggérée : trait Decrire { fn nom(&self) -> String; fn decrire(&self) -> String { /* défaut */ } }.
  • Cas de test : un Chat qui ne définit que nom (renvoyant "un chat") -> decrire() = "Ceci est un chat" ; un type qui redéfinit decrire -> sa propre chaîne.

Point<T> et somme des coordonnées

Définir struct Point<T> { x: T, y: T } et une méthode somme(&self) -> T qui renvoie x + y, disponible seulement lorsque T supporte l'addition.

  • Objectif : impl<T: ...> avec contrainte (std::ops::Add<Output = T> + Copy).
  • Signature suggérée : impl<T: Add<Output = T> + Copy> Point<T> { fn somme(&self) -> T }.
  • Cas de test : Point { x: 3, y: 4 }.somme() -> 7, Point { x: 1.5, y: 2.5 }.somme() -> 4.0.