Sovrascrivere le implementazioni predefinite
Fa parte della sezione Programmazione orientata agli oggetti del percorso Rust di Coddy. Lezione 32 di 61.
Le implementazioni predefinite sono comode, ma a volte un tipo ha bisogno di un comportamento diverso da quello standard. Quando succede, puoi sovrascrivere il comportamento predefinito fornendo una tua implementazione nel blocco impl.
Ti basta definire il metodo con la stessa firma, ma includendo la tua logica personalizzata:
trait Greet {
fn greet(&self) -> String {
String::from("Hello there!")
}
}
struct Robot {
id: u32,
}
impl Greet for Robot {
fn greet(&self) -> String {
format!("BEEP BOOP. Unit {} online.", self.id)
}
}
Anche se Greet fornisce un metodo greet predefinito, Robot lo sostituisce completamente con la propria versione. Quando chiami greet() su un Robot, Rust usa l’implementazione personalizzata:
let bot = Robot { id: 42 };
println!("{}", bot.greet()); // BEEP BOOP. Unità 42 in linea.
Questo ti offre flessibilità: i tipi che si accontentano dell'implementazione predefinita non devono scrivere nulla, mentre i tipi che necessitano di un comportamento specializzato possono sovrascrivere solo i metodi che servono loro. Il trait garantisce comunque che ogni tipo che lo implementa abbia il metodo a disposizione.
Sfida
FacileCostruiamo un sistema di notifiche in cui diversi tipi di avviso possono personalizzare i propri messaggi! Creerai un trait con un'implementazione predefinita, poi farai in modo che un tipo usi quella predefinita mentre un altro la sovrascriva con un comportamento personalizzato.
Organizzerai il codice in tre file:
notifiable.rs: Definisci un trait pubblicoNotifiablecon un metodonotify(&self) -> Stringche ha un'implementazione predefinita che restituisce"Alert: Something happened!".alerts.rs: Crea due struct pubbliche che implementano il trait in modi diversi:GenericAlert: una struct unitaria che usa la notifica predefinita (blocco impl vuoto)UrgentAlert: una struct con un campo pubblicomessage(String) che sovrascrive il comportamento predefinito per restituire"URGENT: {message}", dove{message}è il messaggio memorizzato
main.rs: Riunisci i moduli e mostra entrambi i comportamenti. Crea unGenericAlerte unUrgentAlertusando l'input fornito, quindi stampa le loro notifiche.
L'idea chiave è che GenericAlert ottiene gratuitamente il comportamento predefinito, mentre UrgentAlert fornisce una propria versione specializzata definendo il metodo nel suo blocco impl.
L'output deve seguire questo formato:
Alert: Something happened!
URGENT: {message}Per esempio, con l'input Server is down!:
Alert: Something happened!
URGENT: Server is down!Riceverai un input: il messaggio per l'avviso urgente.
Provalo tu
mod notifiable;
mod alerts;
use alerts::{GenericAlert, UrgentAlert};
use notifiable::Notifiable;
fn main() {
// Leggi l'input per il messaggio di avviso urgente
let mut input = String::new();
std::io::stdin().read_line(&mut input).expect("Failed to read line");
let message = input.trim().to_string();
// TODO: Crea un'istanza di GenericAlert
// TODO: Crea un'istanza di UrgentAlert con il messaggio di input
// TODO: Stampa la notifica di GenericAlert
// TODO: Stampa la notifica di UrgentAlert
}
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