0Pricing
Go Academy · Lezione

Definire e implementare le interfacce

Soddisfacimento implicito e interfaccia vuota

Definire e implementare le interfacce è una lezione Go Academy gratuita su CoddyKit. Questa è la lezione 1 di 4. Puoi leggere la lezione completa qui gratuitamente — poi esercitati direttamente nel browser con un editor di codice integrato e un tutor IA disponibile 24/7. Fa parte del percorso di apprendimento Go Academy, e i tuoi progressi si sincronizzano tra il web e l'app CoddyKit. Il corso Go Academy include 4 lezioni in totale.

Che cos'è un'interfaccia?

Un'interfaccia in Go è un insieme di firme di metodi. Qualsiasi tipo che implementa tutti questi metodi soddisfa implicitamente l'interfaccia: non è necessaria alcuna parola chiave implements. Questo meccanismo è chiamato tipizzazione strutturale o duck typing.

Dichiarare un'interfaccia

Definisca un'interfaccia con la parola chiave type:

package main
import "fmt"

type Shape interface {
    Area() float64
    Perimeter() float64
}

type Circle struct{ Radius float64 }
func (c Circle) Area() float64      { return 3.14159 * c.Radius * c.Radius }
func (c Circle) Perimeter() float64 { return 2 * 3.14159 * c.Radius }

func main() {
    var s Shape = Circle{5}
    fmt.Printf("Area: %.2f\n", s.Area())
}

Soddisfazione implicita

Non è necessaria alcuna dichiarazione di intenti. Se un tipo dispone dei metodi corretti, soddisfa automaticamente l'interfaccia:

package main
import "fmt"

type Greeter interface{ Greet() string }

type English struct{}
func (e English) Greet() string { return "Hello" }

type Spanish struct{}
func (s Spanish) Greet() string { return "Hola" }

func say(g Greeter) { fmt.Println(g.Greet()) }

func main() {
    say(English{})
    say(Spanish{})
}

L'interfaccia vuota

interface{} (o any in Go 1.18+) è soddisfatta da ogni tipo. Viene usata quando il tipo non è noto in fase di compilazione:

package main
import "fmt"

func printAny(v any) { fmt.Printf("%T: %v\n", v, v) }

func main() {
    printAny(42)
    printAny("hello")
    printAny([]int{1,2,3})
}

Valori di interfaccia

Un valore di interfaccia contiene due elementi: un tipo concreto e un valore concreto. Un'interfaccia nil ha entrambi impostati a nil:

package main
import "fmt"

type Animal interface{ Sound() string }
type Dog struct{}
func (d Dog) Sound() string { return "woof" }

func main() {
    var a Animal
    fmt.Println(a == nil) // true
    a = Dog{}
    fmt.Println(a == nil) // false
    fmt.Println(a.Sound())
}

Soddisfare più interfacce

Un tipo può soddisfare contemporaneamente più interfacce:

package main
import "fmt"

type Reader interface{ Read() string }
type Writer interface{ Write(string) }
type ReadWriter interface{ Reader; Writer }

type File struct{ content string }
func (f *File) Read() string       { return f.content }
func (f *File) Write(s string)     { f.content = s }

func main() {
    var rw ReadWriter = &File{}
    rw.Write("hello")
    fmt.Println(rw.Read())
}

Assegnazione tra interfacce

Un'interfaccia più ampia può contenere un valore concreto di tipo più specifico. Per assegnare un valore tra tipi di interfaccia, il tipo concreto deve soddisfare entrambe le interfacce:

package main
import "fmt"

type Stringer interface{ String() string }

type Point struct{ X, Y int }
func (p Point) String() string { return fmt.Sprintf("(%d,%d)", p.X, p.Y) }

func main() {
    var s Stringer = Point{3, 4}
    fmt.Println(s.String())
}

Trappola dell'interfaccia nil

Un'interfaccia non nil che contiene un valore concreto nil NON è uguale a nil:

package main
import "fmt"

type MyErr struct{}
func (e *MyErr) Error() string { return "oops" }

func bad() error {
    var e *MyErr // nil pointer
    return e     // returns non-nil interface!
}

func main() {
    err := bad()
    fmt.Println(err == nil) // false — common gotcha
}

Le interfacce facilitano i test

Definire le dipendenze come interfacce consente di sostituire le implementazioni reali con mock nei test:

package main
import "fmt"

type EmailSender interface{ Send(to, body string) error }

type MockSender struct{ Sent []string }
func (m *MockSender) Send(to, body string) error {
    m.Sent = append(m.Sent, to)
    return nil
}

func notify(s EmailSender, addr string) { s.Send(addr, "hello") }

func main() {
    mock := &MockSender{}
    notify(mock, "a@b.com")
    fmt.Println(mock.Sent) // [a@b.com]
}

Accettare interfacce, restituire struct

Una best practice di Go: i parametri delle funzioni dovrebbero essere interfacce (per offrire flessibilità), mentre i tipi restituiti dovrebbero essere concreti (così i chiamanti sanno che cosa ricevono):

package main

type Logger interface{ Log(string) }

type FileLogger struct{}
func (f *FileLogger) Log(s string) {}

func NewFileLogger() *FileLogger { // returns concrete
    return &FileLogger{}
}

func process(l Logger) {} // accepts interface

func main() { process(NewFileLogger()) }

Mantenga le interfacce piccole

La libreria standard di Go privilegia interfacce ridotte: io.Reader ha un metodo, così come io.Writer. Le interfacce piccole sono più componibili e più facili da simulare nei test.

Verifica rapida

Un tipo deve dichiarare di implementare un'interfaccia?

Riepilogo: interfacce

Punti chiave:

  • Le interfacce definiscono comportamenti, non dati
  • La soddisfazione è implicita: non è necessaria la parola chiave implements
  • L'interfaccia vuota (any) accetta qualsiasi tipo
  • Presti attenzione alla trappola dell'interfaccia nil
  • Mantenga le interfacce piccole e focalizzate

Esercizio

Definisca un'interfaccia Storage con Save(key, value string) error e Load(key string) (string, error). La implementi con una MemStorage basata su una map e la sottoponga a test.

Domande Frequenti

La lezione «Definire e implementare le interfacce» è gratuita?

Sì — il testo completo di «Definire e implementare le interfacce» è gratuito qui sul web. Per esercitarvi in modo interattivo (un editor di codice integrato e un tutor IA 24/7) e sbloccare il resto del corso Go Academy, passa a CoddyKit PRO. Il corso Go Academy include 4 lezioni in totale.

Cosa imparerò in «Definire e implementare le interfacce»?

Soddisfacimento implicito e interfaccia vuota Eserciti Go Academy con codice pratico che esegui direttamente nel browser, e un tutor IA 24/7 risponde alle tue domande mentre lavori sulla lezione.

Ho bisogno di esperienza per iniziare Go Academy?

Non è richiesta alcuna esperienza precedente. Go Academy su CoddyKit è strutturato per principianti e studenti avanzati, quindi puoi iniziare da qui o dall'inizio e procedere al tuo ritmo. Questa è la lezione 1 di 4.

Quanto tempo richiede la lezione «Definire e implementare le interfacce»?

La maggior parte delle lezioni CoddyKit richiede circa 5–10 minuti. Ogni lezione è breve e interattiva, quindi fai progressi costanti e riprendi esattamente da dove hai lasciato su web e app.

Posso scrivere ed eseguire codice in questa lezione Go Academy?

Sì. Ogni lezione Go Academy include un editor di codice integrato, quindi scrivi ed esegui codice reale direttamente nel tuo browser e ricevi feedback istantaneo dall'IA — nessuna configurazione locale necessaria.

Tutte le lezioni di questo corso

  1. Definire e implementare le interfacce
  2. Interfacce fondamentali della libreria standard
  3. Asserzioni di tipo e switch sul tipo
  4. Composizione delle interfacce e buone pratiche
← Torna a Go Academy