So schreiben Sie Switch-Anweisungen in Go

Einführung

Conditional statements geben Programmierern die Möglichkeit, ihre Programme anzuweisen, eine Aktion auszuführen, wenn eine Bedingung wahr ist, und eine andere Aktion, wenn die Bedingung falsch ist. Häufig möchten wir einigevariable mit mehreren möglichen Werten vergleichen und unter den jeweiligen Umständen unterschiedliche Maßnahmen ergreifen. Es ist möglich, dass dies nur mitif statements funktioniert. Beim Schreiben von Software geht es jedoch nicht nur darum, Dinge zum Laufen zu bringen, sondern auch darum, Ihre Absichten Ihrem zukünftigen Selbst und anderen Entwicklern mitzuteilen. switch ist eine alternative bedingte Anweisung, die nützlich ist, um Aktionen zu kommunizieren, die von Ihren Go-Programmen ausgeführt werden, wenn verschiedene Optionen angezeigt werden.

Alles, was wir mit der switch-Anweisung schreiben können, kann auch mitif-Anweisungen geschrieben werden. In diesem Tutorial sehen wir uns einige Beispiele an, wie die switch-Anweisung funktionieren kann, welcheif-Anweisungen sie ersetzt und wo sie am besten angewendet wird.

Struktur von Schalteranweisungen

Switch wird häufig verwendet, um die Aktionen zu beschreiben, die ein Programm ausführt, wenn einer Variablen bestimmte Werte zugewiesen werden. Das folgende Beispiel zeigt, wie wir dies mit den Anweisungen voniferreichen würden:

package main

import "fmt"

func main() {
    flavors := []string{"chocolate", "vanilla", "strawberry", "banana"}

    for _, flav := range flavors {
        if flav == "strawberry" {
            fmt.Println(flav, "is my favorite!")
            continue
        }

        if flav == "vanilla" {
            fmt.Println(flav, "is great!")
            continue
        }

        if flav == "chocolate" {
            fmt.Println(flav, "is great!")
            continue
        }

        fmt.Println("I've never tried", flav, "before")
    }
}

Dies erzeugt die folgende Ausgabe:

Outputchocolate is great!
vanilla is great!
strawberry is my favorite!
I've never tried banana before

Innerhalb vonmain definieren wirslice der Eissorten. Wir verwenden dann einfor loop, um sie zu durchlaufen. Wir verwenden dreiif-Anweisungen, um verschiedene Nachrichten auszudrucken, die die Präferenzen für verschiedene Eissorten angeben. Jedeif-Anweisung muss diecontinue-Anweisung verwenden, um die Ausführung derfor-Schleife zu stoppen, damit die Standardnachricht am Ende nicht für die bevorzugten Eiscremearomen gedruckt wird.

Wenn wir neue Eiscreme-Einstellungen hinzufügen, müssen wir weiterhinif Anweisungen hinzufügen, um die neuen Fälle zu behandeln. Doppelte Nachrichten müssen, wie im Fall von"vanilla" und"chocolate", doppelteif-Anweisungen enthalten. Für zukünftige Leser unseres Codes (wir selbst eingeschlossen) verdeckt die Wiederholung derif-Anweisungen den wichtigen Teil ihrer Arbeit - den Vergleich der Variablen mit mehreren Werten und das Ergreifen verschiedener Aktionen. Außerdem unterscheidet sich unsere Fallback-Meldung von den Bedingungen, sodass sie nicht in Zusammenhang zu stehen scheint. Die Anweisungswitchkann uns helfen, diese Logik besser zu organisieren.

Die Anweisungswitch beginnt mit dem Schlüsselwortswitch und wird in ihrer grundlegendsten Form von einer Variablen gefolgt, mit der Vergleiche durchgeführt werden können. Darauf folgt ein Paar geschweifte Klammern ({}), in denen mehrerecase clauses auftreten können. Case-Klauseln beschreiben die Aktionen, die Ihr Go-Programm ausführen sollte, wenn die in der switch-Anweisung angegebene Variable dem Wert entspricht, auf den die Case-Klausel verweist. Im folgenden Beispiel wird das vorherige Beispiel so konvertiert, dassswitch anstelle mehrererif-Anweisungen verwendet wird:

package main

import "fmt"

func main() {
    flavors := []string{"chocolate", "vanilla", "strawberry", "banana"}

    for _, flav := range flavors {
        switch flav {
        case "strawberry":
            fmt.Println(flav, "is my favorite!")
        case "vanilla", "chocolate":
            fmt.Println(flav, "is great!")
        default:
            fmt.Println("I've never tried", flav, "before")
        }
    }
}

Die Ausgabe ist die gleiche wie zuvor:

Outputchocolate is great!
vanilla is great!
strawberry is my favorite!
I've never tried banana before

Wir haben erneut eine Scheibe Eiscremearomen inmain definiert und die Anweisungrange verwendet, um über jedes Aroma zu iterieren. Dieses Mal haben wir jedoch eineswitch-Anweisung verwendet, die dieflav-Variable untersucht. Wir verwenden zweicase-Klauseln, um Präferenzen anzugeben. Wir brauchen keinecontinue-Anweisungen mehr, da nur einecase-Klausel von derswitch-Anweisung ausgeführt wird. Wir können auch die doppelte Logik der"chocolate"- und"vanilla"-Bedingungen kombinieren, indem wir sie in der Deklaration dercase-Klausel jeweils durch ein Komma trennen. Diedefault-Klausel dient als Sammelklausel. Es wird für alle Geschmacksrichtungen ausgeführt, die wir im Hauptteil derswitch-Anweisung nicht berücksichtigt haben. In diesem Fall führt"banana" zur Ausführung vondefault und druckt die NachrichtI've never tried banana before.

Diese vereinfachte Form derswitch-Anweisungen behandelt die häufigste Verwendung für sie: den Vergleich einer Variablen mit mehreren Alternativen. Es bietet uns auch Vorteile, wenn wir dieselbe Aktion für mehrere verschiedene Werte und eine andere Aktion ausführen möchten, wenn keine der aufgelisteten Bedingungen mit dem angegebenen Schlüsselwortdefaulterfüllt ist.

Wenn sich diese vereinfachte Form vonswitch als zu einschränkend erweist, können wir eine allgemeinere Form derswitch-Anweisung verwenden.

Allgemeine Schalteranweisungen

Die Anweisungen vonswitchind nützlich, um Sammlungen komplizierterer Bedingungen zu gruppieren, um zu zeigen, dass sie irgendwie zusammenhängen. Dies wird am häufigsten verwendet, wenn eine Variable mit einem Wertebereich verglichen wird, und nicht mit bestimmten Werten wie im vorherigen Beispiel. Das folgende Beispiel implementiert ein Ratespiel mitif-Anweisungen, die von einerswitch-Anweisung profitieren könnten:

package main

import (
    "fmt"
    "math/rand"
    "time"
)

func main() {
    rand.Seed(time.Now().UnixNano())
    target := rand.Intn(100)

    for {
        var guess int
        fmt.Print("Enter a guess: ")
        _, err := fmt.Scanf("%d", &guess)
        if err != nil {
            fmt.Println("Invalid guess: err:", err)
            continue
        }

        if guess > target {
            fmt.Println("Too high!")
            continue
        }

        if guess < target {
            fmt.Println("Too low!")
            continue
        }

        fmt.Println("You win!")
        break
    }
}

Die Ausgabe variiert abhängig von der ausgewählten Zufallszahl und davon, wie gut Sie das Spiel spielen. Hier ist die Ausgabe einer Beispielsitzung:

OutputEnter a guess: 10
Too low!
Enter a guess: 15
Too low!
Enter a guess: 18
Too high!
Enter a guess: 17
You win!

Unser Ratespiel benötigt eine Zufallszahl, mit der wir die Vermutungen vergleichen können. Daher verwenden wir die Funktionrand.Intnaus dem Paketmath/rand. Um sicherzustellen, dass wir jedes Mal, wenn wir das Spiel spielen, unterschiedliche Werte fürtarget erhalten, verwenden wirrand.Seed, um den Zufallszahlengenerator basierend auf der aktuellen Zeit zu randomisieren. Das Argument100 bisrand.Intn gibt uns eine Zahl im Bereich von 0 bis 100. Wir verwenden dann einefor-Schleife, um Vermutungen vom Spieler zu sammeln.

Die Funktionfmt.Scanfgibt uns die Möglichkeit, Benutzereingaben in eine Variable unserer Wahl einzulesen. Es wird ein Format-String-Verb benötigt, das die Benutzereingaben in den von uns erwarteten Typ konvertiert. %d bedeutet hier, dass wirint erwarten und die Adresse der Variablenguess übergeben, damitfmt.Scanf diese Variable setzen kann. Nachhandling any parsing errors verwenden wir dann zweiif-Anweisungen, um die Vermutung des Benutzers mit dem Wert vontargetzu vergleichen. Diestring, die sie zurückgeben, steuern zusammen mitbool die dem Spieler angezeigte Meldung und ob das Spiel beendet wird.

Dieseif-Anweisungen verschleiern die Tatsache, dass der Wertebereich, mit dem die Variable verglichen wird, alle in irgendeiner Weise zusammenhängen. Es kann auch schwierig sein, auf einen Blick festzustellen, ob wir einen Teil des Sortiments verpasst haben. Im nächsten Beispiel wird das vorherige Beispiel überarbeitet, um stattdessen eineswitch-Anweisung zu verwenden:

package main

import (
    "fmt"
    "math/rand"
)

func main() {
    target := rand.Intn(100)

    for {
        var guess int
        fmt.Print("Enter a guess: ")
        _, err := fmt.Scanf("%d", &guess)
        if err != nil {
            fmt.Println("Invalid guess: err:", err)
            continue
        }

        switch {
        case guess > target:
            fmt.Println("Too high!")
        case guess < target:
            fmt.Println("Too low!")
        default:
            fmt.Println("You win!")
            return
        }
    }
}

Dadurch wird eine Ausgabe ähnlich der folgenden generiert:

OutputEnter a guess: 25
Too low!
Enter a guess: 28
Too high!
Enter a guess: 27
You win!

In dieser Version des Ratespiels haben wir den Block der Anweisungen vonifdurch eine Anweisung vonswitchersetzt. Wir lassen das Ausdrucksargument fürswitch weg, da wir nur daran interessiert sind,switch zu verwenden, um Bedingungen zusammen zu sammeln. Jedecase-Klausel enthält einen anderen Ausdruck, derguess mittarget vergleicht. Ähnlich wie beim ersten Ersetzen vonif Anweisungen durchswitch benötigen wir keinecontinue Anweisungen mehr, da nur einecase Klausel ausgeführt wird. Schließlich behandelt diedefault-Klausel den Fall, in demguess == target, da wir alle anderen möglichen Werte mit den anderen zweicase-Klauseln abgedeckt haben.

In den bisher gezeigten Beispielen wird genau eine case-Anweisung ausgeführt. Gelegentlich möchten Sie möglicherweise das Verhalten mehrerercase-Klauseln kombinieren. Die Anweisungen vonswitchbieten ein weiteres Schlüsselwort, um dieses Verhalten zu erreichen.

Durchfallen

Manchmal möchten Sie den Code, den eine anderecase-Klausel enthält, wiederverwenden. In diesen Fällen können Sie Go bitten, den Text der nächstencase-Klausel auszuführen, die mit dem Schlüsselwortfallthroughaufgelistet ist. Dieses nächste Beispiel modifiziert unser früheres Eisgeschmacksbeispiel, um unsere Begeisterung für Erdbeereis genauer widerzuspiegeln:

package main

import "fmt"

func main() {
    flavors := []string{"chocolate", "vanilla", "strawberry", "banana"}

    for _, flav := range flavors {
        switch flav {
        case "strawberry":
            fmt.Println(flav, "is my favorite!")
            fallthrough
        case "vanilla", "chocolate":
            fmt.Println(flav, "is great!")
        default:
            fmt.Println("I've never tried", flav, "before")
        }
    }
}

Wir werden diese Ausgabe sehen:

Outputchocolate is great!
vanilla is great!
strawberry is my favorite!
strawberry is great!
I've never tried banana before

Wie wir bereits gesehen haben, definieren wir einen Slice vonstring, um Aromen darzustellen, und durchlaufen diesen mithilfe einerfor-Schleife. Die Anweisungswitch hier ist identisch mit der zuvor gesehenen, jedoch mit dem Schlüsselwortfallthrough am Ende der Klauselcase für"strawberry". Dadurch führt Go den Body voncase "strawberry": aus und druckt zuerst die Zeichenfolgestrawberry is my favorite! aus. Wenn es auffallthrough trifft, wird der Hauptteil der nächstencase-Klausel ausgeführt. Dadurch wird der Body voncase "vanilla", "chocolate": ausgeführt undstrawberry is great! gedruckt.

Das Schlüsselwortfallthroughwird von Go-Entwicklern nicht häufig verwendet. Normalerweise kann die unter Verwendung vonfallthrough realisierte Code-Wiederverwendung besser erhalten werden, indem eine Funktion mit dem gemeinsamen Code definiert wird. Aus diesen Gründen wird generell von der Verwendung vonfallthrough abgeraten.

Fazit

Die Anweisungen vonswitchhelfen uns, anderen Entwicklern, die unseren Code lesen, zu vermitteln, dass eine Reihe von Vergleichen in irgendeiner Weise miteinander zusammenhängen. Sie erleichtern das Hinzufügen eines anderen Verhaltens, wenn in Zukunft ein neuer Fall hinzugefügt wird, und ermöglichen es sicherzustellen, dass alles, was wir vergessen haben, auch mitdefault-Klauseln ordnungsgemäß behandelt wird. Wenn Sie das nächste Mal mehrereif-Anweisungen schreiben, die alle dieselbe Variable enthalten, versuchen Sie, sie mit einerswitch-Anweisung neu zu schreiben. Sie werden es einfacher finden, sie zu überarbeiten, wenn es an der Zeit ist, eine andere Alternative in Betracht zu ziehen Wert.

Wenn Sie mehr über die Programmiersprache Go erfahren möchten, lesen Sie die gesamtenHow To Code in Go series.