Menu
Coddy logo textTech

Implémentations par défaut

Fait partie de la section Object Oriented Programming du Journey Rust de Coddy — leçon 31 sur 61.

Jusqu'à présent, chaque méthode de trait que nous avons définie n'était qu'une signature — une exigence sans corps. Mais que se passerait-il si la plupart des types implémentant un trait utilisaient la même logique ? Rust vous permet de fournir une implémentation par défaut directement dans la définition du trait.

Au lieu de terminer la signature de la méthode par un point-virgule, vous ajoutez un corps :

trait Greet {
    fn greet(&self) -> String {
        String::from("Hello there!")
    }
}

Désormais, tout type qui implémente Greet reçoit automatiquement cette méthode — sans écrire de code dans le bloc impl :

struct Guest;

impl Greet for Guest {}

let visitor = Guest;
println!("{}", visitor.greet());  // Bonjour !

L'implémentation vide impl Greet for Guest {} est valide car le trait fournit déjà le comportement. La structure « choisit » simplement d'adhérer au trait et reçoit la méthode par défaut gratuitement.

Ce modèle est utile lorsque vous souhaitez définir un comportement partagé qui fonctionne dans la plupart des cas. Les types qui nécessitent quelque chose de différent peuvent surcharger le comportement par défaut (ce que vous apprendrez ensuite), tandis que les types qui se contentent du comportement standard n'ont pas besoin de se répéter.

challenge icon

Défi

Facile

Explorons la puissance des implémentations par défaut en construisant un système de notification ! Vous allez créer un trait qui fournit un comportement standard prêt à l'emploi, afin que les types puissent l'adopter sans écrire de code répétitif.

Vous organiserez votre code sur trois fichiers :

  • notifiable.rs : Définissez un trait public Notifiable avec une méthode notify(&self) -> String qui possède une implémentation par défaut. La valeur par défaut doit retourner "You have a new notification!". Tout type implémentant ce trait recevra automatiquement ce comportement sans avoir besoin d'écrire quoi que ce soit dans son bloc impl.
  • alerts.rs : Créez deux structures d'unité (unit structs) publiques simples qui implémentent votre trait :
    • EmailAlert — implémente Notifiable avec un bloc impl vide (utilise la valeur par défaut)
    • SystemAlert — implémente également Notifiable avec un bloc impl vide (utilise la valeur par défaut)
    Les deux structures recevront automatiquement le message de notification par défaut sans que vous n'ayez à écrire de corps de méthode !
  • main.rs : Rassemblez vos modules et démontrez comment les deux types d'alerte partagent le même comportement par défaut. Créez des instances des deux structures et appelez leurs méthodes notify.

Dans votre fichier principal, créez un EmailAlert et un SystemAlert, puis affichez leurs notifications sur des lignes séparées.

Votre sortie devrait être :

You have a new notification!
You have a new notification!

Remarquez comment les deux types produisent une sortie identique — c'est toute la beauté des implémentations par défaut ! Aucune des structures n'a eu besoin d'écrire de code pour la méthode notify, et pourtant les deux ont un comportement de notification pleinement fonctionnel. Dans la prochaine leçon, vous apprendrez comment surcharger ces valeurs par défaut lorsqu'un type nécessite un comportement personnalisé.

Aide-mémoire

Les méthodes de trait peuvent avoir des implémentations par défaut en fournissant un corps de méthode au lieu d'une simple signature :

trait Greet {
    fn greet(&self) -> String {
        String::from("Hello there!")
    }
}

Les types implémentant le trait reçoivent automatiquement le comportement par défaut sans avoir à écrire de code :

struct Guest;

impl Greet for Guest {}

let visitor = Guest;
println!("{}", visitor.greet());  // Hello there!

Un bloc impl vide est valide lorsque le trait fournit des implémentations par défaut. Cela permet aux types d'adhérer à un comportement partagé sans répétition.

Essayez vous-même

mod notifiable;
mod alerts;

use notifiable::Notifiable;
use alerts::{EmailAlert, SystemAlert};

fn main() {
    // TODO: Créer une instance de EmailAlert
    
    // TODO: Créer une instance de SystemAlert
    
    // TODO: Afficher la notification de EmailAlert
    
    // TODO: Afficher la notification de SystemAlert
}
quiz iconTestez-vous

Cette leçon comprend un petit quiz. Commencez la leçon pour y répondre et suivre votre progression.

Toutes les leçons de Object Oriented Programming