So konstruieren Sie für Loops in Go

Einführung

Bei der Computerprogrammierung ist aloop eine Codestruktur, die sich wiederholt, um einen Code wiederholt auszuführen, häufig bis eine bestimmte Bedingung erfüllt ist. Durch die Verwendung von Schleifen in der Computerprogrammierung können Sie ähnliche Aufgaben mehrmals automatisieren und wiederholen. Stellen Sie sich vor, Sie hätten eine Liste der zu verarbeitenden Dateien oder möchten die Anzahl der Zeilen in einem Artikel zählen. Sie würden eine Schleife in Ihrem Code verwenden, um diese Art von Problemen zu lösen.

In Go implementiert einefor-Schleife die wiederholte Ausführung von Code basierend auf einem Schleifenzähler oder einer Schleifenvariablen. Im Gegensatz zu anderen Programmiersprachen mit mehreren Schleifenkonstrukten wiewhile,do usw. verfügt Go nur über die Schleifefor. Dies dient dazu, Ihren Code klarer und lesbarer zu machen, da Sie sich nicht um mehrere Strategien kümmern müssen, um dasselbe Schleifenkonstrukt zu erzielen. Durch diese verbesserte Lesbarkeit und die geringere kognitive Belastung während der Entwicklung ist Ihr Code auch weniger fehleranfällig als in anderen Sprachen.

In diesem Tutorial erfahren Sie, wie diefor-Schleife von Go funktioniert, einschließlich der drei Hauptvarianten ihrer Verwendung. Zunächst zeigen wir, wie verschiedene Arten vonfor-Schleifen erstellt werden, gefolgt von der Schleife durchsequential data types in Go. Wir werden zum Schluss erklären, wie man verschachtelte Schleifen verwendet.

ForClause- und Condition-Schleifen deklarieren

Um eine Vielzahl von Anwendungsfällen zu berücksichtigen, gibt es drei verschiedene Möglichkeiten,for-Schleifen in Go mit jeweils eigenen Funktionen zu erstellen. Diese dienen zum Erstellen einerfor-Schleife mit einemCondition, einemForClause oder einemRangeClause. In diesem Abschnitt wird erklärt, wie die ForClause- und Condition-Varianten deklariert und verwendet werden.

Schauen wir uns zunächst an, wie wir einefor-Schleife mit der ForClause verwenden können.

EinForClause loop hat eininitial statement, gefolgt von einemcondition und einempost statement. Diese sind in der folgenden Syntax angeordnet:

for [ Initial Statement ] ; [ Condition ] ; [ Post Statement ] {
    [Action]
}

Um zu erklären, was die vorhergehenden Komponenten tun, schauen wir uns einefor-Schleife an, die mithilfe der ForClause-Syntax um einen bestimmten Wertebereich inkrementiert:

for i := 0; i < 5; i++ {
    fmt.Println(i)
}

Lassen Sie uns diese Schleife auflösen und jedes Teil identifizieren.

Der erste Teil der Schleife isti := 0. Dies ist die erste Aussage:

for i := 0; i < 5; i++ {
    fmt.Println(i)
}

Es besagt, dass wir eine Variable namensi deklarieren und den Anfangswert auf0 setzen.

Weiter ist die Bedingung:

for i := 0; i < 5; i++ {
    fmt.Println(i)
}

In diesem Zustand haben wir angegeben, dassi zwar kleiner als der Wert von5 ist, die Schleife jedoch die Schleife fortsetzen sollte.

Schließlich haben wir die Post-Anweisung:

for i := 0; i < 5; i++ {
    fmt.Println(i)
}

In der post-Anweisung erhöhen wir die Schleifenvariablei jedes Mal um eins, wenn eine Iteration mit dem Operatori++increment auftritt.

Wenn wir dieses Programm ausführen, sieht die Ausgabe folgendermaßen aus:

Output0
1
2
3
4

Die Schleife lief 5 mal. Zunächst wurdei auf0 gesetzt und dann überprüft, obi kleiner als5 war. Da der Wert voni kleiner als5 war, wurde die Schleife ausgeführt und die Aktion vonfmt.Println(i) ausgeführt. Nach Beendigung der Schleife wurde die Post-Anweisung voni++ aufgerufen und der Wert voni um 1 erhöht.

[.note] #Note: Beachten Sie, dass wir bei der Programmierung tendenziell bei Index 0 beginnen. Obwohl 5 Zahlen ausgedruckt werden, reichen sie von 0 bis 4
#

Wir sind nicht darauf beschränkt, bei 0 zu beginnen oder bei einem bestimmten Wert zu enden. Wir können unserer anfänglichen Anweisung einen beliebigen Wert zuweisen und auch bei einem beliebigen Wert in unserer post-Anweisung aufhören. Auf diese Weise können wir einen beliebigen Bereich zum Durchlaufen erstellen:

for i := 20; i < 25; i++ {
    fmt.Println(i)
}

Hier reicht die Iteration von 20 (einschließlich) bis 25 (ausschließlich), sodass die Ausgabe folgendermaßen aussieht:

Output20
21
22
23
24

Wir können auch unsere post-Anweisung verwenden, um bei verschiedenen Werten zu inkrementieren. Dies ähneltstep in anderen Sprachen:

Verwenden wir zunächst eine post-Anweisung mit einem positiven Wert:

for i := 0; i < 15; i += 3 {
    fmt.Println(i)
}

In diesem Fall wird diefor-Schleife so eingerichtet, dass die Zahlen von 0 bis 15 ausgedruckt werden, jedoch in Schritten von 3, so dass nur jede dritte Zahl wie folgt gedruckt wird:

Output0
3
6
9
12

Wir können auch einen negativen Wert für unser Argument nach der Anweisung verwenden, um rückwärts zu iterieren. Wir müssen jedoch unsere Argumente für die ursprüngliche Anweisung und die Bedingung entsprechend anpassen:

for i := 100; i > 0; i -= 10 {
    fmt.Println(i)
}

Hier setzen wiri auf einen Anfangswert von100, verwenden die Bedingungi < 0, um bei0 anzuhalten, und die Post-Anweisung verringert den Wert um 10 mit-= Operator. Die Schleife beginnt bei100 und endet bei0 und nimmt mit jeder Iteration um 10 ab. Wir können dies in der Ausgabe sehen:

Output100
90
80
70
60
50
40
30
20
10

Sie können auch die anfängliche Anweisung und die post-Anweisung von der Syntax vonforausschließen und nur die Bedingung verwenden. Dies ist alsCondition loop bekannt:

i := 0
for i < 5 {
    fmt.Println(i)
    i++
}

Dieses Mal haben wir die Variablei getrennt von derfor-Schleife in der vorhergehenden Codezeile deklariert. Die Schleife hat nur eine Bedingungsklausel, die prüft, obi kleiner als5 ist. Solange die Bedingungtrue ergibt, wird die Schleife weiter iteriert.

Manchmal wissen Sie möglicherweise nicht, wie viele Iterationen Sie benötigen, um eine bestimmte Aufgabe auszuführen. In diesem Fall können Sie alle Anweisungen weglassen und das Schlüsselwortbreakverwenden, um die Ausführung zu beenden:

for {
    if someCondition {
        break
    }
    // do action here
}

Ein Beispiel hierfür könnte sein, wenn wir aus einer unbestimmt großen Struktur wiebuffer lesen und nicht wissen, wann wir mit dem Lesen fertig sind:

buffer.go

package main

import (
    "bytes"
    "fmt"
    "io"
)

func main() {
    buf := bytes.NewBufferString("one\ntwo\nthree\nfour\n")

    for {
        line, err := buf.ReadString('\n')
        if err != nil {
            if err == io.EOF {

                fmt.Print(line)
                break
            }
            fmt.Println(err)
            break
        }
        fmt.Print(line)
    }
}

Im vorhergehenden Code deklariertbuf :=bytes.NewBufferString("one two three four ") einen Puffer mit einigen Daten. Da wir nicht wissen, wann der Puffer das Lesen beendet, erstellen wir einefor-Schleife ohne Klausel. Innerhalb derfor-Schleife lesen wir mitline, err := buf.ReadString(' ') eine Zeile aus dem Puffer und prüfen, ob beim Lesen aus dem Puffer ein Fehler aufgetreten ist. Wenn ja, beheben wir den Fehler unduse the break keyword to exit the for loop. Mit diesenbreak Punkten müssen Sie keine Bedingung einschließen, um die Schleife zu stoppen.

In diesem Abschnitt haben wir gelernt, wie eine ForClause-Schleife deklariert und zum Durchlaufen eines bekannten Wertebereichs verwendet wird. Wir haben auch gelernt, wie man mit einer Bedingungsschleife iteriert, bis eine bestimmte Bedingung erfüllt ist. Als Nächstes erfahren Sie, wie die RangeClause zum Durchlaufen sequenzieller Datentypen verwendet wird.

Sequentielle Datentypen mit RangeClause durchlaufen

In Go werden häufigfor-Schleifen verwendet, um die Elemente von sequentiellen oder Sammlungsdatentypen wieslices, arrays undstrings zu durchlaufen. Um dies zu vereinfachen, können wir einefor-Schleife mitRangeClause-Syntax verwenden. Während Sie sequentielle Datentypen mithilfe der ForClause-Syntax durchlaufen können, ist RangeClause übersichtlicher und einfacher zu lesen.

Bevor wir uns mit der RangeClause befassen, wollen wir uns ansehen, wie wir mithilfe der ForClause-Syntax durch ein Segment iterieren können:

main.go

package main

import "fmt"

func main() {
    sharks := []string{"hammerhead", "great white", "dogfish", "frilled", "bullhead", "requiem"}

    for i := 0; i < len(sharks); i++ {
        fmt.Println(sharks[i])
    }
}

Wenn Sie dies ausführen, erhalten Sie die folgende Ausgabe, bei der jedes Element des Slice ausgedruckt wird:

Outputhammerhead
great white
dogfish
frilled
bullhead
requiem

Verwenden Sie jetzt die RangeClause, um dieselben Aktionen auszuführen:

main.go

package main

import "fmt"

func main() {
    sharks := []string{"hammerhead", "great white", "dogfish", "frilled", "bullhead", "requiem"}

    for i, shark := range sharks {
        fmt.Println(i, shark)
    }
}

In diesem Fall drucken wir jedes Element in der Liste aus. Obwohl wir die Variableni undshark verwendet haben, hätten wir die Variable auch alle anderenvalid variable name nennen können und würden die gleiche Ausgabe erhalten:

Output0 hammerhead
1 great white
2 dogfish
3 frilled
4 bullhead
5 requiem

Wenn Sierange für ein Slice verwenden, werden immer zwei Werte zurückgegeben. Der erste Wert ist der Index, in dem sich die aktuelle Iteration der Schleife befindet, und der zweite Wert ist der Wert an diesem Index. In diesem Fall betrug der Index für die erste Iteration0 und der Werthammerhead.

Manchmal wollen wir nur den Wert innerhalb der Slice-Elemente, nicht den Index. Wenn wir den vorhergehenden Code ändern, um nur den Wert auszudrucken, erhalten wir einen Fehler bei der Kompilierung:

main.go

package main

import "fmt"

func main() {
    sharks := []string{"hammerhead", "great white", "dogfish", "frilled", "bullhead", "requiem"}

    for i, shark := range sharks {
        fmt.Println(shark)
    }
}
Outputsrc/range-error.go:8:6: i declared and not used

Dai in derfor-Schleife deklariert, aber nie verwendet wird, antwortet der Compiler mit dem Fehleri declared and not used. Dies ist derselbe Fehler, den Sie in Go erhalten, wenn Sie eine Variable deklarieren und nicht verwenden.

Aus diesem Grund hat Goblank identifier, was ein Unterstrich (_) ist. In einerfor-Schleife können Sie den leeren Bezeichner verwenden, um alle vom Schlüsselwortrange zurückgegebenen Werte zu ignorieren. In diesem Fall möchten wir den Index ignorieren, der das erste zurückgegebene Argument ist.

main.go

package main

import "fmt"

func main() {
    sharks := []string{"hammerhead", "great white", "dogfish", "frilled", "bullhead", "requiem"}

    for _, shark := range sharks {
        fmt.Println(shark)
    }
}
Outputhammerhead
great white
dogfish
frilled
bullhead
requiem

Diese Ausgabe zeigt, dass diefor-Schleife durch das String-Slice iteriert und jedes Element aus dem Slice ohne Index gedruckt hat.

Sie können auchrange verwenden, um Elemente zu einer Liste hinzuzufügen:

main.go

package main

import "fmt"

func main() {
    sharks := []string{"hammerhead", "great white", "dogfish", "frilled", "bullhead", "requiem"}

    for range sharks {
        sharks = append(sharks, "shark")
    }

    fmt.Printf("%q\n", sharks)
}
Output['hammerhead', 'great white', 'dogfish', 'frilled', 'bullhead', 'requiem', 'shark', 'shark', 'shark', 'shark', 'shark', 'shark']

Hier haben wir für jedes Element der Länge dessharks-Slice eine Platzhalterzeichenfolge von"shark" hinzugefügt.

Beachten Sie, dass wir den leeren Bezeichner_ nicht verwenden mussten, um einen der Rückgabewerte des Operatorsrange zu ignorieren. Mit Go können wir den gesamten Deklarationsteil derrange-Anweisung weglassen, wenn wir keinen der Rückgabewerte verwenden müssen.

Wir können auch den Operatorrange verwenden, um Werte eines Slice einzugeben:

main.go

package main

import "fmt"

func main() {
    integers := make([]int, 10)
    fmt.Println(integers)

    for i := range integers {
        integers[i] = i
    }

    fmt.Println(integers)
}

In diesem Beispiel wird das Sliceintegers mit zehn leeren Werten initialisiert, aber diefor-Schleife setzt alle Werte in der Liste wie folgt:

Output[0 0 0 0 0 0 0 0 0 0]
[0 1 2 3 4 5 6 7 8 9]

Wenn wir zum ersten Mal den Wert des Sliceintegers drucken, sehen wir alle Nullen. Dann durchlaufen wir jeden Index und setzen den Wert auf den aktuellen Index. Wenn wir dann den Wert vonintegers ein zweites Mal drucken, zeigt dies, dass alle jetzt einen Wert von0 bis9 haben.

Wir können auch den Operatorrange verwenden, um jedes Zeichen in einer Zeichenfolge zu durchlaufen:

main.go

package main

import "fmt"

func main() {
    sammy := "Sammy"

    for _, letter := range sammy {
        fmt.Printf("%c\n", letter)
    }
}
OutputS
a
m
m
y

Beim Durchlaufen vonmap gibtrange sowohlkey als auchvalue zurück:

main.go

package main

import "fmt"

func main() {
    sammyShark := map[string]string{"name": "Sammy", "animal": "shark", "color": "blue", "location": "ocean"}

    for key, value := range sammyShark {
        fmt.Println(key + ": " + value)
    }
}
Outputcolor: blue
location: ocean
name: Sammy
animal: shark

[.note] #Note: Es ist wichtig zu beachten, dass die Reihenfolge, in der eine Karte zurückgegeben wird, zufällig ist. Jedes Mal, wenn Sie dieses Programm ausführen, erhalten Sie möglicherweise ein anderes Ergebnis.
#

Nachdem wir nun gelernt haben, wie sequentielle Daten mitrangefor-Schleifen durchlaufen werden, schauen wir uns an, wie Schleifen innerhalb von Schleifen verwendet werden.

Geschachtelt für Schleifen

Schleifen können in Go wie in anderen Programmiersprachen verschachtelt werden. Nesting ist, wenn wir ein Konstrukt in einem anderen haben. In diesem Fall ist eine verschachtelte Schleife eine Schleife, die in einer anderen Schleife auftritt. Diese können nützlich sein, wenn Sie eine Schleifenaktion für jedes Element eines Datensatzes ausführen möchten.

Verschachtelte Schleifen ähneln strukturellnested if statements. Sie sind so aufgebaut:

for {
    [Action]
    for {
        [Action]
    }
}

Das Programm trifft zuerst auf die äußere Schleife und führt ihre erste Iteration aus. Diese erste Iteration löst die innere, verschachtelte Schleife aus, die dann vollständig ausgeführt wird. Dann kehrt das Programm an den Anfang der äußeren Schleife zurück, schließt die zweite Iteration ab und löst erneut die verschachtelte Schleife aus. Die verschachtelte Schleife wird wieder vollständig ausgeführt, und das Programm kehrt an den Anfang der äußeren Schleife zurück, bis die Sequenz abgeschlossen ist oder eine Unterbrechung oder eine andere Anweisung den Prozess unterbricht.

Implementieren wir eine verschachteltefor-Schleife, damit wir genauer hinschauen können. In diesem Beispiel durchläuft die äußere Schleife eine Schicht von Ganzzahlen, die alsnumList bezeichnet wird, und die innere Schleife durchläuft eine Schicht von Zeichenfolgen, die alsalphaList bezeichnet wird.

main.go

package main

import "fmt"

func main() {
    numList := []int{1, 2, 3}
    alphaList := []string{"a", "b", "c"}

    for _, i := range numList {
        fmt.Println(i)
        for _, letter := range alphaList {
            fmt.Println(letter)
        }
    }
}

Wenn wir dieses Programm ausführen, erhalten wir die folgende Ausgabe:

Output1
a
b
c
2
a
b
c
3
a
b
c

Die Ausgabe zeigt, dass das Programm die erste Iteration der äußeren Schleife durch Drucken von1 abschließt, was dann die Fertigstellung der inneren Schleife auslöst und nacheinandera,b,c druckt . Sobald die innere Schleife abgeschlossen ist, kehrt das Programm zum oberen Rand der äußeren Schleife zurück, druckt2 und druckt dann erneut die innere Schleife in ihrer Gesamtheit (a,b,c) s) usw.

Verschachteltefor-Schleifen können nützlich sein, um Elemente in Slices zu durchlaufen, die aus Slices bestehen. Wenn wir in einem aus Slices zusammengesetzten Slice nur einefor-Schleife verwenden, gibt das Programm jede interne Liste als Element aus:

main.go

package main

import "fmt"

func main() {
    ints := [][]int{
        []int{0, 1, 2},
        []int{-1, -2, -3},
        []int{9, 8, 7},
    }

    for _, i := range ints {
        fmt.Println(i)
    }
}
Output[0 1 2]
[-1 -2 -3]
[9 8 7]

Um auf jedes einzelne Element der internen Slices zuzugreifen, implementieren wir eine verschachteltefor-Schleife:

main.go

package main

import "fmt"

func main() {
    ints := [][]int{
        []int{0, 1, 2},
        []int{-1, -2, -3},
        []int{9, 8, 7},
    }

    for _, i := range ints {
        for _, j := range i {
            fmt.Println(j)
        }
    }
}
Output0
1
2
-1
-2
-3
9
8
7

Wenn wir hier eine verschachteltefor-Schleife verwenden, können wir die einzelnen in den Slices enthaltenen Elemente durchlaufen.

Fazit

In diesem Tutorial haben wir gelernt, wie manfor-Schleifen deklariert und verwendet, um sich wiederholende Aufgaben in Go zu lösen. Wir haben auch die drei verschiedenen Variationen einerfor-Schleife und den Zeitpunkt ihrer Verwendung kennengelernt. Lesen SieUsing Break and Continue Statements When Working with Loops in Go, um mehr überfor-Schleifen und deren Steuerung zu erfahren.