Vai al contenuto
eLearner.app
Modulo 6 · Lezione 1 di 526/50 nel corso~12 min
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

Go
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

Go
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

Go
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

Go
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 T sia di *T.
  • Metodi a pointer receiver stanno SOLO nel method set di *T.

Conseguenza pratica:

Go
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) NO

Quando un metodo ha pointer receiver, devi assegnare un puntatore alla variabile interfaccia.

Prova tu

Esercizio#go.m6.l1.e1
Tentativi: 0Caricamento…

Definisci un'interfaccia Greeter con un solo metodo Greet() string.

Caricamento editor…
Mostra suggerimento

Sintassi: `type Name interface { Method(args) return }`.

Soluzione disponibile dopo 3 tentativi

Esercizio#go.m6.l1.e2
Tentativi: 0Caricamento…

Implementa Greeter su un nuovo tipo Robot con campo ID string; il metodo ritorna 'bip ' + ID.

Caricamento editor…
Mostra suggerimento

Niente `implements`: basta definire il metodo con la firma giusta.

Soluzione disponibile dopo 3 tentativi

Quiz#go.m6.l1.e3
Pronto

Come dichiari che il tipo P implementa l'interfaccia Greeter?

Go
type P struct{}
// ?
Opzioni di risposta

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 *T soddisfa l'interfaccia.
  • Polimorfismo Go: parametri di tipo interfaccia, niente gerarchie.