Comment écrire des instructions de commutateur en un clic

introduction

Conditional statements donne aux programmeurs la possibilité de diriger leurs programmes pour qu'ils entreprennent une action si une condition est vraie et une autre action si la condition est fausse. Souvent, nous voulons comparer certainsvariable à plusieurs valeurs possibles, en prenant des actions différentes dans chaque circonstance. Il est possible de faire fonctionner cela en utilisant uniquementif statements. Cependant, écrire un logiciel ne consiste pas seulement à faire fonctionner les choses, mais aussi à communiquer votre intention à votre futur développeur et aux autres développeurs. switch est une instruction conditionnelle alternative utile pour communiquer les actions entreprises par vos programmes Go lorsqu'ils sont présentés avec différentes options.

Tout ce que nous pouvons écrire avec l'instruction switch peut également être écrit avec les instructionsif. Dans ce didacticiel, nous allons examiner quelques exemples de ce que l’instruction switch peut faire, les instructionsif qu’elle remplace et où elle est le plus appliquée.

Structure des instructions de commutation

Switch est couramment utilisé pour décrire les actions entreprises par un programme lorsqu'une variable se voit attribuer des valeurs spécifiques. L'exemple suivant montre comment nous accomplirions cela en utilisant les instructionsif:

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")
    }
}

Cela générera la sortie suivante:

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

Enmain, nous définissons unslice d'arômes de glace. Nous utilisons ensuite unfor loop pour les parcourir. Nous utilisons trois instructionsifpour imprimer différents messages indiquant les préférences pour différentes saveurs de glace. Chaque instructionif doit utiliser l'instructioncontinue pour arrêter l'exécution de la bouclefor afin que le message par défaut à la fin ne soit pas imprimé pour les saveurs de glace préférées.

Au fur et à mesure que nous ajoutons de nouvelles préférences pour la crème glacée, nous devons continuer à ajouter des instructionsif pour gérer les nouveaux cas. Les messages dupliqués, comme dans le cas de"vanilla" et"chocolate", doivent avoir des instructionsif dupliquées. Pour les futurs lecteurs de notre code (nous y compris), la nature répétitive des instructionsif obscurcit la partie importante de ce qu'elles font - comparer la variable à plusieurs valeurs et entreprendre différentes actions. De plus, notre message de secours est mis à part des conditions, ce qui le rend non apparenté. L'instructionswitch peut nous aider à mieux organiser cette logique.

L'instructionswitch commence par le mot-cléswitch et est suivie, dans sa forme la plus élémentaire, d'une variable avec laquelle effectuer des comparaisons. Ceci est suivi d'une paire d'accolades ({}) où plusieurscase clauses peuvent apparaître. Les clauses case décrivent les actions que votre programme Go doit entreprendre lorsque la variable fournie à l'instruction switch est égale à la valeur référencée par la clause case. L'exemple suivant convertit l'exemple précédent pour utiliser unswitch au lieu de plusieurs instructionsif:

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")
        }
    }
}

La sortie est la même que précédemment:

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

Nous avons une fois de plus défini une tranche de saveurs de glace enmain et utilisé l'instructionrange pour parcourir chaque saveur. Cette fois, cependant, nous avons utilisé une instructionswitch qui examinera la variableflav. Nous utilisons deux clausescase pour indiquer les préférences. Nous n'avons plus besoin d'instructionscontinue car une seule clausecase sera exécutée par l'instructionswitch. Nous sommes également en mesure de combiner la logique dupliquée des conditionnelles"chocolate" et"vanilla" en séparant chacune par une virgule dans la déclaration de la clausecase. La clausedefault sert de clause fourre-tout. Il fonctionnera pour toutes les saveurs que nous n'avons pas prises en compte dans le corps de l'instructionswitch. Dans ce cas,"banana" provoquera l'exécution dedefault, imprimant le messageI've never tried banana before.

Cette forme simplifiée d'instructionsswitch répond à leur utilisation la plus courante: comparer une variable à plusieurs alternatives. Cela nous permet également d'effectuer la même action pour plusieurs valeurs différentes et une autre action lorsqu'aucune des conditions répertoriées n'est remplie à l'aide du mot clédefault fourni.

Lorsque cette forme simplifiée deswitch s'avère trop limitative, nous pouvons utiliser une forme plus générale de l'instructionswitch.

Déclarations générales de commutation

Les instructionsswitch sont utiles pour grouper des collections de conditionnelles plus compliquées afin de montrer qu'elles sont en quelque sorte liées. Ceci est le plus souvent utilisé lors de la comparaison de certaines variables avec une plage de valeurs, plutôt que des valeurs spécifiques comme dans l'exemple précédent. L'exemple suivant implémente un jeu de devinettes à l'aide d'instructionsif qui pourraient bénéficier d'une instructionswitch:

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
    }
}

La sortie varie en fonction du nombre aléatoire sélectionné et de la qualité de votre jeu. Voici le résultat d'un exemple de session:

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

Notre jeu de devinettes a besoin d'un nombre aléatoire pour comparer les suppositions, nous utilisons donc la fonctionrand.Intn du packagemath/rand. Pour nous assurer d'obtenir des valeurs différentes pourtarget à chaque fois que nous jouons au jeu, nous utilisonsrand.Seed pour randomiser le générateur de nombres aléatoires en fonction de l'heure actuelle. L'argument100 àrand.Intn nous donnera un nombre compris entre 0 et 100. Nous utilisons ensuite une bouclefor pour commencer à collecter les suppositions du joueur.

La fonctionfmt.Scanf nous donne un moyen de lire l'entrée utilisateur dans une variable de notre choix. Il faut un verbe de chaîne de formatage qui convertit les entrées de l’utilisateur dans le type que nous attendons. %d ici signifie que nous attendons unint, et nous passons l'adresse de la variableguess afin quefmt.Scanf puisse définir cette variable. Aprèshandling any parsing errors, nous utilisons ensuite deux instructionsif pour comparer la supposition de l'utilisateur à la valeur detarget. Lesstring qu'ils retournent, ainsi que lesbool, contrôlent le message affiché au joueur et si le jeu va se terminer.

Ces instructionsif masquent le fait que la plage de valeurs à laquelle la variable est comparée sont toutes liées d'une manière ou d'une autre. Il peut également être difficile, en un coup d'œil, de dire si nous avons oublié une partie de la plage. L'exemple suivant refactorise l'exemple précédent pour utiliser une instructionswitch à la place:

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
        }
    }
}

Cela générera une sortie similaire à celle-ci:

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

Dans cette version du jeu de devinettes, nous avons remplacé le bloc d'instructionsif par une instructionswitch. Nous omettons l'argument expression deswitch car nous ne sommes intéressés qu'à utiliserswitch pour collecter les conditions ensemble. Chaque clausecase contient une expression différente comparantguess àtarget. Comme la première fois que nous avons remplacé les instructionsif parswitch, nous n'avons plus besoin d'instructionscontinue puisqu'une seule clausecase sera exécutée. Enfin, la clausedefault gère le cas oùguess == target puisque nous avons couvert toutes les autres valeurs possibles avec les deux autres clausescase.

Dans les exemples que nous avons vus jusqu’à présent, une seule instruction case sera exécutée. Parfois, vous souhaiterez peut-être combiner les comportements de plusieurs clausescase. Les instructionsswitch fournissent un autre mot-clé pour obtenir ce comportement.

Tomber dans

Parfois, vous souhaiterez réutiliser le code qu'une autre clausecase contient. Dans ces cas, il est possible de demander à Go d'exécuter le corps de la clausecase suivante répertoriée à l'aide du mot cléfallthrough. Cet exemple suivant modifie notre exemple précédent d'arôme de crème glacée pour mieux refléter notre enthousiasme pour la crème glacée à la fraise:

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")
        }
    }
}

Nous verrons cette sortie:

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

Comme nous l'avons vu précédemment, nous définissons une tranche destring pour représenter les saveurs et l'itérons en utilisant une bouclefor. L'instructionswitch ici est identique à celle que nous avons vue auparavant, mais avec l'ajout du mot-cléfallthrough à la fin de la clausecase pour"strawberry". Cela obligera Go à exécuter le corps decase "strawberry":, en imprimant d'abord la chaînestrawberry is my favorite!. Lorsqu'il rencontrefallthrough, il exécute le corps de la clausecase suivante. Cela entraînera l'exécution du corps decase "vanilla", "chocolate":, imprimantstrawberry is great!.

Le mot cléfallthrough n'est pas souvent utilisé par les développeurs Go. Habituellement, la réutilisation de code réalisée en utilisantfallthrough peut être mieux obtenue en définissant une fonction avec le code commun. Pour ces raisons, l'utilisation defallthrough est généralement déconseillée.

Conclusion

Les instructionsswitch nous aident à faire comprendre aux autres développeurs qui lisent notre code qu'un ensemble de comparaisons sont en quelque sorte liés les uns aux autres. Ils facilitent grandement l'ajout d'un comportement différent lorsqu'un nouveau cas est ajouté à l'avenir et permettent de s'assurer que tout ce que nous avons oublié est également traité correctement avec les clausesdefault. La prochaine fois que vous vous surprendrez à écrire plusieurs instructionsif qui impliquent toutes la même variable, essayez de la réécrire avec une instructionswitch - il vous sera plus facile de retravailler quand viendra le temps d'envisager une autre alternative valeur.

Si vous souhaitez en savoir plus sur le langage de programmation Go, consultez l'intégralité desHow To Code in Go series.