Menu
Coddy logo textTech

Duck typing in Go

Fa parte della sezione Programmazione orientata agli oggetti del percorso GO di Coddy. Lezione 42 di 107.

Il termine duck typing deriva dal detto: "Se cammina come un'anatra e fa qua qua come un'anatra, allora è un'anatra." In Go, questo significa che un tipo non deve dichiarare esplicitamente di implementare un'interfaccia. Deve solo avere i metodi giusti.

Considera questa interfaccia e due tipi completamente non correlati:

type Quacker interface {
    Quack() string
}

type Duck struct{}
func (d Duck) Quack() string { return "Quack!" }

type Robot struct{}
func (r Robot) Quack() string { return "Beep-quack!" }

Né Duck né Robot menzionano Quacker in alcun punto delle loro definizioni. Eppure entrambi soddisfano l’interfaccia semplicemente perché hanno un metodo Quack() con la firma corretta:

func MakeItQuack(q Quacker) {
    fmt.Println(q.Quack())
}

func main() {
    MakeItQuack(Duck{})   // Quack!
    MakeItQuack(Robot{})  // Beep-quack!
}

Questa soddisfazione implicita è potente perché ti permette di definire interfacce dopo che i tipi esistono già. Puoi creare un’interfaccia che corrisponda ai tipi di pacchetti esterni senza modificarne il codice sorgente. I tipi non devono conoscere la tua interfaccia. Devono solo comportarsi correttamente.

Il duck typing in Go ti offre la flessibilità dei linguaggi dinamici mantenendo la sicurezza dei tipi in fase di compilazione. Il compilatore verifica che i tipi dispongano effettivamente dei metodi richiesti prima di consentirne l'uso come valori di interfaccia.

challenge icon

Sfida

Facile

Costruiamo un sistema di messaggistica che dimostri il duck typing in azione. Creerai tipi completamente indipendenti che possono tutti inviare messaggi tramite un’interfaccia comune, senza che nessuno di essi dichiari esplicitamente di implementarla.

Organizzerai il codice in tre file:

  • messengers.go: Crea tre struct indipendenti che condividono lo stesso comportamento:
    • Phone con un campo Number. Il suo metodo SendMessage(text string) string restituisce SMS to [Number]: [text]
    • Computer con un campo Email. Il suo metodo SendMessage(text string) string restituisce Email to [Email]: [text]
    • Pigeon con un campo Name. Il suo metodo SendMessage(text string) string restituisce [Name] carries: [text]
    Nota che nessuno di questi tipi menziona alcuna interfaccia. Semplicemente, hanno la stessa firma del metodo.
  • sender.go: Definisci un’interfaccia Messenger che richiede un metodo SendMessage(text string) string. Crea una funzione chiamata Broadcast che accetta una slice di Messenger e una stringa contenente un messaggio, quindi restituisce una slice di stringhe con il risultato della chiamata a SendMessage su ciascun messaggero.
  • main.go: Leggi i dati dall’input, crea un elemento per ciascun tipo di messaggero, raccoglili in una slice di Messenger e usa Broadcast per inviare un messaggio tramite tutti. Stampa ogni risultato su una riga separata.

Verranno forniti i seguenti input:

  • Riga 1: Numero di telefono
  • Riga 2: Indirizzo email
  • Riga 3: Nome del piccione
  • Riga 4: Messaggio da inviare a tutti

Ad esempio, dati 555-1234, alice@mail.com, Winston e Hello World, l’output dovrebbe essere:

SMS to 555-1234: Hello World
Email to alice@mail.com: Hello World
Winston carries: Hello World

L’intuizione fondamentale è che Phone, Computer e Pigeon non hanno nulla in comune. Non condividono un tipo base e non implementano esplicitamente Messenger. Eppure, poiché tutti «starnazzano» allo stesso modo (hanno il metodo corrispondente), Go consente di usarli tutti come valori Messenger. Questo è il duck typing in azione.

Provalo tu

package main

import (
	"bufio"
	"fmt"
	"os"
)

func main() {
	scanner := bufio.NewScanner(os.Stdin)
	
	// Leggi il numero di telefono
	scanner.Scan()
	phoneNumber := scanner.Text()
	
	// Leggi l'indirizzo email
	scanner.Scan()
	email := scanner.Text()
	
	// Leggi il nome del piccione
	scanner.Scan()
	pigeonName := scanner.Text()
	
	// Leggi il messaggio da trasmettere
	scanner.Scan()
	message := scanner.Text()
	
	// TODO: Crea un'istanza per ogni tipo di messaggero (Phone, Computer, Pigeon)
	
	// TODO: Raccogli tutti i messaggeri in uno slice di Messenger
	
	// TODO: Usa Broadcast per inviare il messaggio tramite tutti i messaggeri
	
	// TODO: Stampa ogni risultato su una riga separata
	
	// Segnaposto per utilizzare le variabili (rimuovere durante l'implementazione)
	_ = phoneNumber
	_ = email
	_ = pigeonName
	_ = message
}
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 Go online