Zum Inhalt springen
Go Anfรคnger 25 min

if, switch & Schleifen

Kontrollstrukturen in Go: if mit Init-Statement, switch mit impliziten Breaks und die eine, einzige for-Schleife.

Aktualisiert:
Inhaltsverzeichnis

Kontrollstrukturen in Go

Go hat bewusst wenige Kontrollstrukturen - aber jede davon hat ein paar nette Extras.

if / else

alter := 18

if alter >= 18 {
    fmt.Println("Volljaehrig")
} else if alter >= 16 {
    fmt.Println("Fast volljaehrig")
} else {
    fmt.Println("Zu jung")
}

Merke dir:

  • Keine Klammern um die Bedingung
  • Die { muss auf derselben Zeile stehen
  • Bedingung muss ein bool sein (kein 0/1, kein Truthy)
  • Bloecke sind Pflicht, auch bei einer Zeile

if mit Init-Statement

Ein Go-Feature, das du schnell lieben wirst: Du kannst innerhalb des if eine Variable deklarieren.

if wert, err := strconv.Atoi("42"); err == nil {
    fmt.Println("Zahl:", wert)
} else {
    fmt.Println("Fehler:", err)
}

Vorteil: wert und err sind nur innerhalb des if-Blocks sichtbar - kein Muell im umgebenden Scope.

switch

Goโ€™s switch ist maechtiger als in C/Java:

Einfacher Switch

tag := "Dienstag"

switch tag {
case "Montag":
    fmt.Println("Wochenstart")
case "Dienstag", "Mittwoch", "Donnerstag":
    fmt.Println("Mitte der Woche")
case "Freitag":
    fmt.Println("Bald Wochenende")
default:
    fmt.Println("Wochenende")
}

Kein fallthrough per Default

In C/Java laeuft der case weiter bis zum break. In Go ist jeder case automatisch beendet. Wenn du wirklich weiterlaufen willst, musst du fallthrough schreiben:

switch n {
case 1:
    fmt.Println("Eins")
    fallthrough
case 2:
    fmt.Println("Zwei oder eins")
}

Switch ohne Ausdruck

Ein switch ohne Wert wirkt wie eine if/else-Kette:

punkte := 85

switch {
case punkte >= 90:
    fmt.Println("A")
case punkte >= 80:
    fmt.Println("B")
case punkte >= 70:
    fmt.Println("C")
default:
    fmt.Println("Durchgefallen")
}

Oft lesbarer als eine lange if/else if/else-Kette.

Type-Switch

Wenn du den konkreten Typ eines Interfaces pruefen willst:

func beschreibe(v interface{}) {
    switch x := v.(type) {
    case int:
        fmt.Println("int:", x)
    case string:
        fmt.Println("string:", x)
    case bool:
        fmt.Println("bool:", x)
    default:
        fmt.Println("unbekannter Typ")
    }
}

for - die einzige Schleife in Go

Go hat keine while- oder do-Schleife. Alles laeuft ueber for - in verschiedenen Formen.

Klassische Zaehlschleife

for i := 0; i < 5; i++ {
    fmt.Println(i) // 0, 1, 2, 3, 4
}

Wie ein while

n := 10
for n > 0 {
    fmt.Println(n)
    n--
}

Endlosschleife

for {
    fmt.Println("Unendlich")
    if stopBedingung() {
        break
    }
}

for range

Das Arbeitstier fuer Sammlungen:

namen := []string{"Max", "Anna", "Leo"}

for index, name := range namen {
    fmt.Printf("%d: %s\n", index, name)
}

// Nur den Wert, Index ignorieren
for _, name := range namen {
    fmt.Println(name)
}

// Nur den Index
for index := range namen {
    fmt.Println(index)
}

Der Unterstrich _ heisst โ€œdas will ich nichtโ€. Er ist ein Go-Idiom und vermeidet den โ€œdeclared and not usedโ€-Fehler.

Range ueber eine Map

alter := map[string]int{"Anna": 28, "Max": 34}

for name, jahre := range alter {
    fmt.Printf("%s ist %d\n", name, jahre)
}

Achtung: Die Reihenfolge ist zufaellig - Go sortiert Maps nicht.

Range ueber einen String

Iteriert ueber Unicode-Codepunkte (runes), nicht Bytes:

for i, r := range "Gรถ" {
    fmt.Printf("%d: %c\n", i, r)
}
// 0: G
// 1: รถ  (2 Bytes in UTF-8 - daher Index 1, naechster waere 3)

break und continue

Wie erwartet:

for i := 1; i <= 10; i++ {
    if i%2 == 0 {
        continue
    }
    if i > 7 {
        break
    }
    fmt.Println(i) // 1, 3, 5, 7
}

Labels

Bei verschachtelten Schleifen kannst du gezielt eine bestimmte anspringen:

Aussen:
for x := 0; x < 5; x++ {
    for y := 0; y < 5; y++ {
        if x+y == 4 {
            break Aussen
        }
        fmt.Println(x, y)
    }
}

defer - als Bonus

Nicht direkt eine Kontrollstruktur, aber wichtig: defer verschiebt einen Aufruf bis zum Ende der umgebenden Funktion. Oft fuer Aufraeumarbeiten:

func liesDatei() {
    datei, _ := os.Open("/tmp/data")
    defer datei.Close() // laeuft beim Funktionsende, egal wie sie verlassen wird

    // ...
}

Genial zum Aufraeumen, auch wenn mehrere return-Statements im Spiel sind.

Zusammenfassung

  • if ohne Klammern, mit optionalem Init-Statement
  • switch ohne impliziten Fallthrough, Mehrfach-Cases und switch {} fuer if/else-Ketten
  • for ist die einzige Schleife - in drei Varianten (for i; cond; step, for cond, for {})
  • for range ueber Slices, Maps und Strings
  • defer fuer Cleanup am Funktionsende

Im naechsten Kapitel: Funktionen im Detail.

Zurรผck zum Go Kurs