Lezioni del modulo (1/5)
Interfacce: definire un comportamento
Un'interfaccia in Go è un insieme di firme di metodi. Un valore
implementa l'interfaccia se ha tutti quei metodi — niente
implements, niente extends, niente registrazione esplicita. È il
modello che spesso si chiama "structural typing" o "duck typing
statico": il compilatore verifica la conformità alla compilazione, ma
basata sulla forma, non sulle dichiarazioni.
Dichiarare un'interfaccia
type Greeter interface {
Greet() string
}Convenzione: nomi che terminano con -er per interfacce a un solo
metodo (Reader, Writer, Stringer, Closer). Le interfacce piccole
(1–2 metodi) sono idiomatiche: la libreria standard è piena di
interfacce minuscole che si compongono fra loro (io.ReadWriter,
io.ReadCloser, …).
Implementazione implicita
type Person struct{ Name string }
func (p Person) Greet() string {
return "ciao " + p.Name
}
// Person soddisfa Greeter perché ha il metodo richiesto.
var s Greeter = Person{Name: "Ada"}
fmt.Println(s.Greet())Niente parola chiave. Se il tipo ha i metodi, può essere assegnato a una variabile di quel tipo interfaccia. Punto.
Polimorfismo via interfaccia
type Robot struct{ ID string }
func (r Robot) Greet() string { return "bip " + r.ID }
func greet(s Greeter) {
fmt.Println(s.Greet())
}
greet(Person{Name: "Ada"})
greet(Robot{ID: "R2"})greet accetta qualunque tipo che soddisfi Greeter. È il modo Go di
fare polimorfismo: niente gerarchie, solo capability.
L'interfaccia vuota
var x interface{} = 42
var y any = "ciao" // any è alias built-in di interface{}interface{} (o any da Go 1.18) non richiede alcun metodo, quindi
qualunque valore la soddisfa. Utile per container generici, ma per
estrarre il valore concreto serve type assertion o type switch
(prossime lezioni).
Method set: value vs pointer receiver (anteprima)
Ricorda dal Modulo 5:
- Metodi a value receiver stanno nel method set sia di
Tsia di*T. - Metodi a pointer receiver stanno SOLO nel method set di
*T.
Conseguenza pratica:
type Counter struct{ N int }
func (c *Counter) Inc() { c.N++ }
type Incrementer interface { Inc() }
var i Incrementer = &Counter{} // OK: *Counter ha Inc()
// var j Incrementer = Counter{} // ERRORE: Counter (valore) NOQuando un metodo ha pointer receiver, devi assegnare un puntatore alla variabile interfaccia.
Prova tu
Definisci un'interfaccia Greeter con un solo metodo Greet() string.
Mostra suggerimento
Sintassi: `type Name interface { Method(args) return }`.
Soluzione disponibile dopo 3 tentativi
Implementa Greeter su un nuovo tipo Robot con campo ID string; il metodo ritorna 'bip ' + ID.
Mostra suggerimento
Niente `implements`: basta definire il metodo con la firma giusta.
Soluzione disponibile dopo 3 tentativi
Come dichiari che il tipo P implementa l'interfaccia Greeter?
type P struct{}
// ?Recap
- Interfaccia = set di firme di metodi; nessun
implements. - Implementazione implicita: basta avere i metodi della giusta firma.
- Idiomatico: interfacce piccole (1–2 metodi), nomi in
-er. interface{}/any: accetta qualunque valore, perde type safety.- Method set: pointer receiver → solo
*Tsoddisfa l'interfaccia. - Polimorfismo Go: parametri di tipo interfaccia, niente gerarchie.