Menu
Coddy logo textTech

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.

challenge icon

Sfida

Facile

Esploriamo 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 pubblico Notifiable con un metodo notify(&self) -> String che 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: implementa Notifiable con un blocco impl vuoto (usa l’implementazione predefinita)
    • SystemAlert: implementa anch’essa Notifiable con un blocco impl vuoto (usa l’implementazione predefinita)
    Entrambe le struct otterranno automaticamente il messaggio di notifica predefinito senza che tu debba scrivere alcun corpo di metodo!
  • 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 metodi notify.

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
}
quiz iconMettiti alla prova

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

Esercitati da solo: Compilatore Rust online