En fait, j'avais aussi en tête les mécanismes de conditionnement de type de Rust qui donnent sa puissance à la composition, mais qui sont plus riches que ça, car permettent aussi des implémentations et définitions conditionnelles. Tout cela se complète bien, et constitue ce paradigme un peu exotique qui m'avait surpris par rapport aux langages à classes.
Prenons un exemple de la librairie std:
1 2 3 4 5 6 7 8 9 10 11 12
| pub trait From<T>: Sized {
fn from(value: T) -> Self;
}
pub trait Into<T>: Sized {
fn into(self) -> T;
}
impl<T, U> Into<U> for T
where U: From<T>, {
fn into(self) -> U { U::from(self) }
} |
Qu'est-ce que cela nous dit? On a deux mécanismes de conversion de types qui sont définis par les traits
From et
Into. Ils sont tout à fait équivalents, mais duaux. Par contre, sur cet exemple, la librairie définit une implémentation automatique de
Into<U> pour des types
T a priori inconnus, si
U implémente
From<T> ; c'est le
impl<T, U: From<T>> Into<U> for T ....
Donc, ce n'est pas un mécanisme d'héritage au sens où on n'a pas de relation d'héritage
"From hérite de Into" (ici, cela n'a pas de sens), par contre, on obtient le comportement de
Into<U> par une sorte de mixin contractuel automatique.
Partager