Go Interfaces & Structs

6 Kernkonzepte
Die wichtigsten Go-Konzepte für Typen, Interfaces und Methoden: struct · interface · Methoden · Embedding · Type Assertion · Generics Go verwendet ein elegantes Typsystem mit Structs für Datenstrukturen und Interfaces für Polymorphismus. Diese Cheatsheet fasst die grundlegenden Konzepte für die objektorientierte Programmierung in Go zusammen.

Structs – Datenstrukturen definieren

type · struct · Felder · Tags
type Person struct { Name string Age int Email string } p := Person{Name: "Anna", Age: 30}

Structs sind zusammengesetzte Datentypen, die Felder (Attribute) gruppieren. Sie sind die Grundlage für Datenmodelle in Go und können auch Methoden haben.

Wichtige Struct-Konzepte

Konzept Beschreibung
Feld-Tags Metadaten für Serialisierung (JSON, XML, etc.)
Anonyme Felder Felder ohne Namen (für Embedding)
Exportierte Felder Großbuchstaben = öffentlich sichtbar
Struct-Literal Initialisierung mit { }
new() Zeiger auf Zero-Value Struct
Beispiele
package main
import "fmt"
// Struct mit JSON-Tags
type User struct {
ID int `json:"id"`
FirstName string `json:"first_name"`
LastName string `json:"last_name"`
Active bool `json:"active"`
}
// Initialisierung
u1 := User{ID: 1, FirstName: "Anna", LastName: "Schmidt", Active: true}
// Ohne Feldnamen (Reihenfolge beachten)
u2 := User{2, "Max", "Müller", false}
// Teilweise Initialisierung
u3 := User{FirstName: "Clara"} // andere Felder werden Zero-Value
// new() für Zeiger
u4 := new(User) // *User mit Zero-Values
// Zugriff auf Felder
fmt.Println(u1.FirstName)
u2.Active = true
fmt.Printf("%+v\n", u3) // {ID:0 FirstName:Clara LastName: Active:false}
Tipp: %+v in fmt.Printf zeigt alle Felder mit Namen an – ideal für Debugging von Structs.

Interfaces – Verträge definieren

type · interface · Methoden-Signaturen
type Speaker interface { Speak() string } type Dog struct {} func (d Dog) Speak() string { return "Wuff" }

Interfaces definieren Methoden-Signaturen. Ein Typ implementiert ein Interface implizit, wenn er alle Methoden des Interfaces besitzt – kein explizites implements wie in anderen Sprachen.

Wichtige Interface-Konzepte

Konzept Beschreibung
Implizite Implementierung Ein Typ implementiert ein Interface automatisch
Leeres Interface interface{} – kann jeden Typ speichern (wie any)
Interface-Wert Enthält Typ und Wert (dynamischer Typ)
Interface-Verschachtelung Mehrere Interfaces in einem kombinieren
Type Assertion Wert aus Interface extrahieren
Beispiele
// Interfaces definieren
type Reader interface {
Read(p []byte) (n int, err error)
}
type Closer interface {
Close() error
}
// Zusammengesetztes Interface
type ReadCloser interface {
Reader
Closer
}
// Implizite Implementierung
type File struct {
name string
}
func (f File) Read(p []byte) (int, error) {
return 0, nil
}
func (f File) Close() error {
return nil
}
// File implementiert Reader, Closer und ReadCloser!
func main() {
var r Reader = File{name: "test.txt"}
fmt.Printf("%T\n", r) // main.File
}
Tipp: Das leere Interface interface{} (oder any seit Go 1.18) kann Werte beliebigen Typs enthalten – ähnlich wie Object in Java oder any in TypeScript.

Methoden – Funktionen an Typen binden

func (receiver) · Wert-Empfänger · Zeiger-Empfänger
type Counter struct { value int } func (c Counter) Value() int { return c.value } func (c *Counter) Increment() { c.value++ }

Methoden sind Funktionen mit einem Empfänger (Receiver). Sie können auf Wert-Empfängern (Counter) oder Zeiger-Empfängern (*Counter) definiert werden. Zeiger-Empfänger können das Objekt modifizieren.

Beispiele
package main
import "fmt"
type Rectangle struct {
Width float64
Height float64
}
// Methode mit Wert-Empfänger (keine Modifikation)
func (r Rectangle) Area() float64 {
return r.Width * r.Height
}
// Methode mit Zeiger-Empfänger (modifiziert das Original)
func (r *Rectangle) Scale(factor float64) {
r.Width *= factor
r.Height *= factor
}
func main() {
r := Rectangle{Width: 10, Height: 5}
fmt.Println(r.Area()) // 50
r.Scale(2)
fmt.Println(r.Area()) // 200
// Methoden auf beliebigen Typen
type MyInt int
func (i MyInt) Double() MyInt { return i * 2 }
x := MyInt(5)
fmt.Println(x.Double()) // 10
}
Tipp: Verwenden Sie Zeiger-Empfänger, wenn Sie das Objekt modifizieren möchten oder wenn der Typ groß ist (Effizienz). Für kleine, unveränderliche Typen sind Wert-Empfänger in Ordnung.

Embedding – Structs und Interfaces kombinieren

anonyme Felder · Promoted Methods
type Animal struct { Name string } type Dog struct { Animal // Embedding (anonymes Feld) Breed string } d := Dog{Animal: Animal{Name: "Rex"}, Breed: "Schäferhund"}

Embedding ermöglicht die Komposition von Structs und Interfaces. Ein eingebettetes Feld erbt alle Methoden und Felder des eingebetteten Typs – ähnlich wie Vererbung, aber flexibler.

Beispiele
package main
import "fmt"
// Struct-Embedding
type Person struct {
Name string
Age int
}
type Employee struct {
Person // Embedding
ID int
Salary float64
}
// Methode auf Person
func (p Person) Greet() string {
return "Hallo " + p.Name
}
func main() {
e := Employee{
Person: Person{Name: "Anna", Age: 30},
ID: 123,
Salary: 50000.0,
}
// Direkter Zugriff auf eingebettete Felder
fmt.Println(e.Name) // Anna (promoted)
fmt.Println(e.Age) // 30
// Methoden des eingebetteten Typs sind verfügbar
fmt.Println(e.Greet()) // Hallo Anna
// Interface-Embedding
type Reader interface { Read() string }
type Writer interface { Write(s string) }
type ReadWriter interface {
Reader
Writer
}
}
Tipp: Embedding ist keine Vererbung – es ist Komposition. Methoden des eingebetteten Typs werden "promoted" und sind direkt auf dem äußeren Typ aufrufbar.

Type Assertion – Typen prüfen und extrahieren

.(type) · switch · type switch
var i interface{} = 42 v, ok := i.(int) // v=42, ok=true switch v := i.(type) { case int: /* ... */ case string: /* ... */ }

Type Assertion extrahiert den konkreten Wert aus einem Interface. Die "comma ok"-Form verhindert Panics, wenn der Typ nicht übereinstimmt. Type Switches erlauben die Abfrage mehrerer Typen.

Beispiele
package main
import "fmt"
func main() {
var val interface{} = "Hallo"
// Type Assertion (unsicher – panic bei Fehler)
s := val.(string)
fmt.Println(s)
// Type Assertion mit "comma ok" (sicher)
n, ok := val.(int)
if ok {
fmt.Println("Zahl:", n)
} else {
fmt.Println("Keine Zahl")
}
// Type Switch
switch v := val.(type) {
case string:
fmt.Printf("String: %s (Länge: %d)\n", v, len(v))
case int:
fmt.Printf("Int: %d\n", v)
case bool:
fmt.Printf("Bool: %t\n", v)
default:
fmt.Printf("Unbekannter Typ: %T\n", v)
}
// Praktisches Beispiel: Prüfen auf Interface
type Stringer interface { String() string }
var s2 interface{} = "test"
if str, ok := s2.(Stringer); ok {
fmt.Println(str.String())
}
}
Tipp: Verwenden Sie immer die "comma ok"-Form für Type Assertions, es sei denn, Sie sind absolut sicher, dass der Typ korrekt ist. Type Switches sind eleganter für mehrere Typ-Abfragen.

Generics – Typen flexibel machen

[T any] · constraints · type parameters
func Print[T any](s []T) { for _, v := range s { fmt.Println(v) } } func Sum[T int | float64](a, b T) T { return a + b }

Generics (seit Go 1.18) ermöglichen die Definition von Funktionen und Typen, die mit verschiedenen Typen arbeiten können – ähnlich wie Templates in anderen Sprachen.

Beispiele
package main
import "fmt"
// Generic Funktion mit any (beliebiger Typ)
func Contains[T comparable](slice []T, element T) bool {
for _, v := range slice {
if v == element { return true }
}
return false
}
// Generic mit Type Constraints (Union)
type Number interface {
~int | ~int64 | ~float64
}
func Add[T Number](a, b T) T {
return a + b
}
// Generic Struct
type Stack[T any] struct {
items []T
}
func (s *Stack[T]) Push(item T) {
s.items = append(s.items, item)
}
func (s *Stack[T]) Pop() T {
item := s.items[len(s.items)-1]
s.items = s.items[:len(s.items)-1]
return item
}
func main() {
s := Stack[string]{}
s.Push("Hallo")
s.Push("Welt")
fmt.Println(s.Pop()) // Welt
fmt.Println(Add(5, 3)) // 8
fmt.Println(Add(5.5, 3.2)) // 8.7
}
Tipp: Das Constraint comparable erlaubt Vergleiche mit == und !=. any ist der neue Name für interface{} und erlaubt jeden Typ.

Go Interfaces & Structs im Überblick

struct Datenstruktur
Felder + Methoden
interface Vertrag
Methoden-Signaturen
func (r T) Methoden
Wert- oder Zeiger-Empfänger
Embedding Komposition
Anonyme Felder
.(type) Type Assertion
Interface-Wert prüfen
[T any] Generics
Typ-Parameter

Quick Summary

struct
Datenstrukturen
interface
Verträge
func (r)
Methoden
Embedding
Komposition
.(type)
Type Assertion
[T]
Generics
type Person struct { Name string } · type Speaker interface { Speak() string }