Traits
Orestis Malaspinas
Trait
permet de dire au compilateur quelles fonctionalités un type doit posséder.On peut contraindre un type générique à avoir un certain trait (trait bound).
fn max<T: PartialOrd>(a: T, b: T) -> T {
if a > b { a } else { b } // si T ne peut pas être ordonné, "<" et ">" n'existent pas
}
Similaire aux interfaces de certains langages.
Exemple:
trait Animal { // définition d'un trait
fn cri(&self) -> String;
fn nom(&self) -> &String;
} // le nombre de méthode est arbitraire
Le compilateur saura que tout type implémentant un trait peut appeler ses méthodes.
trait Animal { // définition d'un trait
fn cri(&self) -> String;
fn nom(&self) -> &String;
} // le nombre de méthode est arbitraire
struct Chien {
nom: String,
}
impl Animal for Chien { // le bloc où les méthodes du trait sont implémentées
fn cri(&self) -> String {
String::from("Ouaf!")
}
fn nom(&self) -> &String {
&self.nom
}
}
fn main() {
let chien = Chien{ nom: String::from("Jack")};
println!("Le cri de {} est {}", chien.nom(), chien.cri());
}
trait Animal { // définition d'un trait
fn cri(&self) -> String;
fn nom(&self) -> &String;
} // le nombre de méthode est arbitraire
struct Chien {
nom: String,
}
impl Animal for Chien { // le bloc où les méthodes du trait sont implémentées
fn cri(&self) -> String {
String::from("Ouaf")
}
fn nom(&self) -> &String {
&self.nom
}
}
struct Chat {
nom: String,
}
impl Animal for Chat { // le bloc où les méthodes du trait sont implémentées
fn cri(&self) -> String {
String::from("Miaou")
}
fn nom(&self) -> &String {
&self.nom
}
}
fn main() {
let chien = Chien{ nom: String::from("Jack")};
println!("Le cri de {} est {}.", chien.nom(), chien.cri());
let chat = Chat{ nom: String::from("Rémy")};
println!("Le cri de {} est {}.", chat.nom(), chat.cri());
}
Il est pratique d’avoir des implémentations par défaut (les mêmes pour tous les types implémentant un trait).
trait Animal { // définition d'un trait
fn cri(&self) -> String;
fn cri_puissant(&self) -> String {
self.cri().to_uppercase()
}
} // le nombre de méthode est arbitraire
struct Chien { }
impl Animal for Chien {
fn cri(&self) -> String {
String::from("Ouaf")
}
}
struct Chat { }
impl Animal for Chat { // le bloc où les méthodes du trait sont implémentées
fn cri(&self) -> String {
String::from("Miaou")
}
}
fn main() {
let chien = Chien{};
println!("Le cri du chien est {} et son cri puissant est {}.",
chien.cri(), chien.cri_puissant());
let chat = Chat{};
println!("Le cri du chat est {} et son cri puissant est {}.",
chat.cri(), chat.cri_puissant());
}
Lors de la définition d’un générique, on peut dire au compilateur si le type implémente un trait.
// Cette fonction ne peut pas foncitonner pour tous les types
// T implémente PartialEq (les opérateurs <, >)
fn max<T: PartialOrd>(a: T, b: T) -> T {
if a > b { a } else { b } // si on peut pas comparer a et b
} // cela ne peut pas compiler, d'où
// le PartialOrd
fn main() {
let a = 1;
let b = 7;
println!("De {} et {}, {} est le plus grand.", a, b, max(a,b));
let a = 1.5;
let b = 7.5;
println!("De {} et {}, {} est le plus grand.", a, b, max(a,b));
}
f64
(le trait Add
et le type f64
) sont dans la librairie standard, donc pas dans une librairie locale.