Go Academy · leksjon

Definere og implementere grensesnitt

Implisitt oppfyllelse og det tomme grensesnittet

Leksjon 1 av 414 trinn

Definere og implementere grensesnitt er en gratis leksjon i Go Academy på CoddyKit. Dette er leksjon 1 av 4. Du kan lese valgfritt 3 leksjoner fra denne læringsstien gratis i sin helhet – deretter låser CoddyKit PRO opp alle leksjoner, samt praktisk øving med en innebygd kodeeditor og en AI-veileder som er tilgjengelig døgnet rundt. Den er en del av læringsløpet i Go Academy, og fremdriften din synkroniseres mellom nettet og CoddyKit-appen. Kurset i Go Academy inneholder totalt 4 leksjoner.

Hva er et grensesnitt?

Et grensesnitt i Go er et sett med metodesignaturer. Alle typer som implementerer alle disse metodene, oppfyller grensesnittet implisitt – du trenger ikke nøkkelordet implements. Dette kalles strukturell typetilordning eller duck typing.

Deklarere et grensesnitt

Definer et grensesnitt med nøkkelordet 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())
}

Implisitt oppfyllelse

Det trengs ingen erklæring om hensikt. Hvis en type har de riktige metodene, oppfyller den grensesnittet automatisk:

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{})
}

Det tomme grensesnittet

interface{} (eller any i Go 1.18+) oppfylles av alle typer. Det brukes når typen er ukjent ved kompilering:

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})
}

Grensesnittverdier

En grensesnittverdi inneholder to ting: en konkret type og en konkret verdi. Et nil-grensesnitt har nil i begge:

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())
}

Oppfyllelse av flere grensesnitt

En type kan oppfylle flere grensesnitt samtidig:

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())
}

Tilordning av grensesnitt

Et bredere grensesnitt kan inneholde en konkret verdi med et snevrere grensesnitt. Tilordning mellom grensesnittstyper krever at den konkrete typen oppfyller begge:

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())
}

Fellen med nil-grensesnitt

Et grensesnitt som ikke er nil, men som inneholder en konkret verdi som er nil, er IKKE lik 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
}

Grensesnitt muliggjør testbarhet

Ved å definere avhengigheter som grensesnitt kan dere bytte ut reelle implementasjoner med mocker i tester:

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]
}

Ta imot grensesnitt, returner strukturer

En god praksis i Go er at funksjonsparametere bør være grensesnitt (for fleksibilitet), mens returtypene bør være konkrete typer (slik at kallere vet hva de får):

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()) }

Hold grensesnittene små

Standardbiblioteket i Go foretrekker små grensesnitt: io.Reader har én metode, og io.Writer har én metode. Små grensesnitt kan kombineres lettere og er enklere å mocke.

Hurtigsjekk

Må en type erklære at den implementerer et grensesnitt?

Oppsummering: grensesnitt

Viktig å ta med seg:

  • Grensesnitt definerer atferd, ikke data
  • Oppfyllelsen er implisitt – ingen nøkkelordet implements
  • Det tomme grensesnittet (any) godtar alle typer
  • Vær oppmerksom på fellen med nil-grensesnitt
  • Hold grensesnittene små og fokuserte

Øvingsoppgave

Definer et Storage-grensesnitt med Save(key, value string) error og Load(key string) (string, error). Implementer det med en MemStorage støttet av en map, og test det.

Gratis å komme i gang

Lær deg Go med en AI-veileder – gratis

Skriv og kjør ekte kode i nettleseren, få umiddelbar hjelp fra en AI-veileder som er tilgjengelig døgnet rundt, og fortsett der du slapp – på nettet eller i appen.

Kurs
51
Leksjoner
203

Ofte stilte spørsmål

Er leksjonen «Definere og implementere grensesnitt» gratis?

Ja – du kan lese valgfritt 3 av leksjonene i læringsstien Go Academy, inkludert «Definere og implementere grensesnitt», gratis i sin helhet her på nettet. Deretter låser CoddyKit PRO opp alle leksjoner, samt interaktiv øving med en innebygd kodeeditor og en AI-veileder som er tilgjengelig døgnet rundt. Kurset i Go Academy inneholder totalt 4 leksjoner.

Hva lærer jeg i «Definere og implementere grensesnitt»?

Implisitt oppfyllelse og det tomme grensesnittet Du øver på Go Academy med praktisk kode som du kjører direkte i nettleseren, mens en AI-veileder som er tilgjengelig døgnet rundt, svarer på spørsmålene dine mens du jobber deg gjennom leksjonen.

Trenger jeg erfaring for å begynne med Go Academy?

Ingen tidligere erfaring er nødvendig. Go Academy på CoddyKit er lagt opp for både nybegynnere og viderekomne, så De kan begynne her eller helt fra start og lære i Deres eget tempo. Dette er leksjon 1 av 4.

Hvor lang tid tar leksjonen «Definere og implementere grensesnitt»?

De fleste CoddyKit-leksjoner tar omtrent 5–10 minutter. Hver leksjon er kort og interaktiv, slik at De gjør jevne fremskritt og kan fortsette akkurat der De slapp – både på nettet og i appen.

Kan jeg skrive og kjøre kode i denne Go Academy-leksjonen?

Ja. Alle Go Academy-leksjoner har en innebygd kodeeditor, slik at De kan skrive og kjøre ekte kode direkte i nettleseren og få umiddelbar tilbakemelding fra AI – uten lokal konfigurering.

Alle leksjonene i dette kurset

  1. Definere og implementere grensesnitt
  2. Sentrale grensesnitt i standardbiblioteket
  3. Typepåstander og typeswitcher
  4. Grensesnittkomposisjon og beste praksis
← Tilbake til Go Academy