Go Funktionen & Methoden

6 Kernkonzepte
Die wichtigsten Konzepte für Funktionen und Methoden in Go: Methoden mit Receivern · Interfaces · Closures · defer · Variadic Functions · init-Funktionen Go bietet eine flexible und elegante Behandlung von Funktionen und Methoden – mit Receivern für Typerweiterungen, Interfaces für Polymorphie und Closures für funktionale Programmierung.

Methoden mit Receivern – Funktionen an Typen binden

func (r Type) methodName() · Wert- und Zeiger-Receiver
type Rectangle struct { Width, Height float64 } func (r Rectangle) Area() float64 { return r.Width * r.Height } func (r *Rectangle) Scale(factor float64) { r.Width *= factor r.Height *= factor }

Methoden sind Funktionen mit einem speziellen Receiver-Argument, das sie an einen Typ bindet. Es gibt Wert-Receiver (Kopie) und Zeiger-Receiver (Modifikation des Originals).

Beispiele
package main
import (
"fmt"
"math"
)
type Circle struct {
Radius float64
}
// Wert-Receiver (erstellt eine Kopie)
func (c Circle) Area() float64 {
return math.Pi * c.Radius * c.Radius
}
// Zeiger-Receiver (modifiziert das Original)
func (c *Circle) SetRadius(r float64) {
c.Radius = r
}
// Methoden für benutzerdefinierte Typen (z.B. string)
type MyString string
func (s MyString) Length() int {
return len(s)
}
func main() {
c := Circle{Radius: 5}
fmt.Println(c.Area()) // 78.5398
c.SetRadius(10)
fmt.Println(c.Area()) // 314.159
s := MyString("Hallo")
fmt.Println(s.Length()) // 5
}
Tipp: Verwenden Sie Zeiger-Receiver, wenn die Methode den Empfänger modifizieren soll oder der Empfänger groß ist. Wert-Receiver sind sicherer, da sie das Original nicht verändern.

Interfaces – Duck-Typing & Polymorphie

interface · Implementierung implizit
type Shape interface { Area() float64 Perimeter() float64 } func printShape(s Shape) { /* ... */ }

Interfaces definieren eine Menge von Methoden. Ein Typ implementiert ein Interface implizit, indem er alle Methoden bereitstellt – ohne explizite Deklaration. Das ist Go's Form von Duck-Typing.

Beispiele
type Shape interface {
Area() float64
}
type Rectangle struct {
Width, Height float64
}
// Rectangle implementiert Shape (implizit)
func (r Rectangle) Area() float64 {
return r.Width * r.Height
}
type Circle struct {
Radius float64
}
// Circle implementiert Shape (implizit)
func (c Circle) Area() float64 {
return math.Pi * c.Radius * c.Radius
}
// Funktion, die Interface erwartet
func printArea(s Shape) {
fmt.Printf("Fläche: %.2f\n", s.Area())
}
func main() {
r := Rectangle{Width: 4, Height: 5}
c := Circle{Radius: 3}
// Beide Typen können an printArea übergeben werden
printArea(r) // Fläche: 20.00
printArea(c) // Fläche: 28.27
// Leeres Interface (jeder Typ)
var anything interface{} = "Hallo"
fmt.Println(anything)
// Type Assertion
str, ok := anything.(string)
if ok {
fmt.Println("Ist ein String:", str)
}
}
Tipp: Interfaces werden in Go implizit implementiert – das macht Code flexibel und fördert lose Kopplung. Ein Typ implementiert ein Interface, wenn er alle Methoden des Interfaces hat.

Closures – Funktionen als Werte

func() · Anonymous Functions · Closures
add := func(a, b int) int { return a + b } func counter() func() int { i := 0 return func() int { i++; return i } }

Closures sind anonyme Funktionen, die auf Variablen aus ihrem umgebenden Scope zugreifen können. Sie sind mächtige Werkzeuge für funktionale Programmierung und State-Management.

Beispiele
package main
import "fmt"
// Counter-Closure
func counter() func() int {
count := 0
return func() int {
count++
return count
}
}
// Closure mit Parameter
func multiplier(factor int) func(x int) int {
return func(x int) int {
return x * factor
}
}
func main() {
// Anonyme Funktion direkt
func() {
fmt.Println("Direkt aufgerufen")
}()
// Counter verwenden
c1 := counter()
fmt.Println(c1()) // 1
fmt.Println(c1()) // 2
c2 := counter() // Unabhängiger Zähler
fmt.Println(c2()) // 1
// Multiplier
double := multiplier(2)
triple := multiplier(3)
fmt.Println(double(5)) // 10
fmt.Println(triple(5)) // 15
}
Tipp: Closures sind ideal für Middleware, Funktionen-Factories oder das Kapseln von Zuständen. Jeder Aufruf der äußeren Funktion erstellt eine neue Closure mit eigenem State.

defer – Ausführung am Ende einer Funktion

defer func() · LIFO-Order
defer fmt.Println("Das wird am Ende ausgeführt") func main() { defer func() { fmt.Println("Dritte") }() defer func() { fmt.Println("Zweite") }() defer func() { fmt.Println("Erste") }() }

defer verzögert die Ausführung eines Funktionsaufrufs bis zum Ende der umgebenden Funktion. Mehrere defer-Aufrufe werden in LIFO-Reihenfolge (Last In, First Out) ausgeführt.

Beispiele
package main
import "fmt"
// Datei-Operation mit defer
func readFile(filename string) {
f, err := os.Open(filename)
if err != nil {
panic(err)
}
defer f.Close() // Datei wird am Ende geschlossen
// Datei lesen...
}
// defer mit Parameter (Werte werden sofort ausgewertet)
func deferExample() {
x := 1
defer fmt.Println(x) // 1 (Wert wird beim defer-Aufruf gespeichert)
x = 2
}
// defer für Fehlerbehandlung
func safeDivision(a, b int) (result int, err error) {
defer func() {
if r := recover(); r != nil {
err = fmt.Errorf("Panic: %v", r)
}
}()
if b == 0 {
panic("Division durch Null")
}
return a / b, nil
}
func main() {
result, err := safeDivision(10, 2)
fmt.Println(result, err) // 5 nil
result, err = safeDivision(10, 0)
fmt.Println(result, err) // 0 Panic: Division durch Null
}
Tipp: defer ist ideal für Aufräumarbeiten (Dateien schließen, Mutex freigeben, DB-Transaktionen beenden). Die LIFO-Reihenfolge ist wichtig für verschachtelte Ressourcen.

Variadic Functions – Beliebige Anzahl von Argumenten

...T · Slice-Expansion
func sum(numbers ...int) int { total := 0 for _, n := range numbers { total += n } return total } sum(1, 2, 3) // 6

Variadic Functions können eine beliebige Anzahl von Argumenten eines Typs entgegennehmen. Das ...-Syntax wandelt die Argumente in ein Slice um.

Beispiele
package main
import "fmt"
// Variadic Function
func join(sep string, parts ...string) string {
result := ""
for i, part := range parts {
if i > 0 {
result += sep
}
result += part
}
return result
}
// Variadic mit unterschiedlichen Typen (interface{})
func printAll(values ...interface{}) {
for _, v := range values {
fmt.Println(v)
}
}
func main() {
fmt.Println(join(", ", "Apfel", "Banane", "Kirsche")) // Apfel, Banane, Kirsche
words := []string{"Go", "ist", "super"}
// Slice-Expansion mit ...
fmt.Println(join(" ", words...)) // Go ist super
printAll(1, "Hallo", true, 3.14)
}
Tipp: Die ...-Syntax kann auch verwendet werden, um ein Slice an eine variadic Function zu übergeben. Das ist eine elegante Möglichkeit, Slices zu expandieren.

init-Funktionen – Automatische Initialisierung

init() · Package-Initialisierung
func init() { // Wird automatisch beim Package-Import ausgeführt fmt.Println("Package initialisiert") }

init-Funktionen werden automatisch beim Import eines Packages ausgeführt – vor der main-Funktion. Sie können in jeder Go-Datei definiert werden und werden in der Reihenfolge ihrer Deklaration ausgeführt.

Beispiele
// config/config.go
package config
import "fmt"
var Config string
// init wird automatisch aufgerufen
func init() {
fmt.Println("Config-Package initialisiert")
Config = "Standard-Konfiguration"
}
// db/db.go
package db
import "fmt"
var DB string
func init() {
fmt.Println("DB-Package initialisiert")
DB = "Datenbankverbindung"
}
// main.go
package main
import (
"fmt"
// Import mit Unterstrich – nur init ausführen
_ "./config"
"./db"
)
func main() {
fmt.Println("main-Funktion")
fmt.Println(db.DB)
}
// Mehrere init-Funktionen in einer Datei
func init() {
fmt.Println("Erste init")
}
func init() {
fmt.Println("Zweite init")
}
Tipp: init-Funktionen werden in der Reihenfolge ihrer Deklaration ausgeführt – zuerst alle init der importierten Packages, dann die der aktuellen Datei. Verwenden Sie sie für Setup-Logik wie das Laden von Konfigurationen.

Go Funktionen & Methoden im Überblick

func Funktionen
Mehrere Rückgabewerte
Receiver Methoden
Wert vs. Zeiger
interface Interfaces
Implizite Implementierung
defer Aufschieben
LIFO-Reihenfolge
... Variadic
Beliebige Argumente
init Initialisierung
Automatisch beim Import

Quick Summary

func (r T)
Methoden
interface
Interfaces
func()
Closures
defer
Aufschieben
...
Variadic
init
Initialisierung
func (r Rectangle) Area() float64 { return r.W * r.H } · defer f.Close() · func sum(nums ...int) int { ... }