if, switch & Schleifen
Kontrollstrukturen in Go: if mit Init-Statement, switch mit impliziten Breaks und die eine, einzige for-Schleife.
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
boolsein (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
ifohne Klammern, mit optionalem Init-Statementswitchohne impliziten Fallthrough, Mehrfach-Cases undswitch {}fuer if/else-Kettenforist die einzige Schleife - in drei Varianten (for i; cond; step,for cond,for {})for rangeueber Slices, Maps und Stringsdeferfuer Cleanup am Funktionsende
Im naechsten Kapitel: Funktionen im Detail.