Implementazioni predefinite
Fa parte della sezione Programmazione orientata agli oggetti del percorso Rust di Coddy. Lezione 31 di 61.
Finora, ogni metodo del trait che abbiamo definito è stato solo una firma: un requisito senza corpo. Ma cosa succede se la maggior parte dei tipi che implementano un trait userebbe la stessa logica? Rust ti consente di fornire un’implementazione predefinita direttamente nella definizione del trait.
Invece di terminare la firma del metodo con un punto e virgola, aggiungi un corpo:
trait Greet {
fn greet(&self) -> String {
String::from("Hello there!")
}
}
Ora qualsiasi tipo che implementa Greet ottiene automaticamente questo metodo, senza scrivere codice nel blocco impl:
struct Guest;
impl Greet for Guest {}
let visitor = Guest;
println!("{}", visitor.greet()); // Ciao!
L’impl Greet for Guest {} vuoto è valido perché il trait fornisce già il comportamento. La struct semplicemente «aderisce» al trait e riceve gratuitamente il metodo predefinito.
Questo schema è utile quando vuoi definire un comportamento condiviso che funzioni nella maggior parte dei casi. I tipi che hanno bisogno di qualcosa di diverso possono sovrascrivere il comportamento predefinito (che imparerai nella prossima lezione), mentre i tipi a cui va bene il comportamento standard non devono ripetersi.
Sfida
FacileEsploriamo la potenza delle implementazioni predefinite creando un sistema di notifiche! Creerai un trait che fornisce un comportamento standard già pronto, così i tipi potranno adottarlo senza scrivere codice ripetitivo.
Organizzerai il codice in tre file:
notifiable.rs: Definisci un trait pubblicoNotifiablecon un metodonotify(&self) -> Stringche ha un’implementazione predefinita. L’implementazione predefinita dovrebbe restituire"You have a new notification!". Qualsiasi tipo che implementa questo trait riceverà automaticamente questo comportamento senza dover scrivere nulla nel proprio blocco impl.alerts.rs: Crea due semplici struct unit pubbliche che implementano il tuo trait:EmailAlert: implementaNotifiablecon un blocco impl vuoto (usa l’implementazione predefinita)SystemAlert: implementa anch’essaNotifiablecon un blocco impl vuoto (usa l’implementazione predefinita)
main.rs: Riunisci i tuoi moduli e mostra come entrambi i tipi di avviso condividono lo stesso comportamento predefinito. Crea istanze di entrambe le struct e chiama i loro metodinotify.
Nel tuo file principale, crea un EmailAlert e un SystemAlert, quindi stampa le loro notifiche su righe separate.
Il tuo output dovrebbe essere:
You have a new notification!
You have a new notification!Nota come entrambi i tipi producono un output identico: è questo il bello delle implementazioni predefinite! Nessuna delle due struct ha dovuto scrivere codice per il metodo notify, eppure entrambe hanno un comportamento di notifica perfettamente funzionante. Nella prossima lezione imparerai a sovrascrivere queste impostazioni predefinite quando un tipo ha bisogno di un comportamento personalizzato.
Provalo tu
mod notifiable;
mod alerts;
use notifiable::Notifiable;
use alerts::{EmailAlert, SystemAlert};
fn main() {
// TODO: Crea un'istanza di EmailAlert
// TODO: Crea un'istanza di SystemAlert
// TODO: Stampa la notifica di EmailAlert
// TODO: Stampa la notifica di SystemAlert
}
Questa lezione include un breve quiz. Inizia la lezione per rispondere e tenere traccia dei tuoi progressi.
Tutte le lezioni di Programmazione orientata agli oggetti
1Metodi e comportamento
Introduzione ai blocchi implIl parametro selfMetodi mutabiliFunzioni associateBlocchi impl multipliConcatenamento di metodiRiepilogo - Azioni sul rettangolo4Progetto: animale domestico virtuale
Definire l'animaleNutrire l'animale7Trait standard
Il trait DebugIl trait DisplayClone e CopyTrait di uguaglianzaRiepilogo - Punto stampabile10Progetto: sistema di documenti
Il trait DrawComponente di testo2Incapsulamento e moduli
Nozioni di base sui moduliLa parola chiave publicCampi privatiGetterSetterRiepilogo - Armadietto sicuro5Generics
Struct genericheMetodi genericiPiù tipi genericiFunzioni genericheRipasso - Punto di coordinate8I Trait come vincoli
Sintassi dei vincoli sui traitVincoli multipliLa clausola whereRestituire tipi con i traitRiepilogo - Stampante generica11Modelli di progettazione in Rust
Pattern NewtypeComposizioneIl trait DropFrom e IntoRipasso - Mock con smart pointer3Enumerazioni avanzate
Enumerazioni con datiMetodi sulle enumerazioniCorrispondenza delle varianti con datiL'enumerazione Option ripresaRiepilogo - enumerazione Shape6Definizione dei trait
Che cos’è un trait?Implementare i traitImplementazioni predefiniteSovrascrivere le implementazioni predefiniteTrait con parametriRiepilogo - Lettore multimedialeEsercitati da solo: Compilatore Rust online