Notes et transcriptions du cours “Démarrer avec Go” proposée par University of California, Irvine disponible sur la plateforme coursera.
Les structures de contrôle permettent de modifier l'ordre dans lequel les instructions sont exécutées dans un programme.
La façon la plus élémentaire d'exécuter un programme consiste simplement à exécuter ses instructions une à une : séquentiellement.
Cette exécution séquentielle peut changer pour de multiples raisons. La première raison pour laquelle le flot d'exécution (flow control) change est que le programmeur insère des structures de contrôle dans son code, ce qui modifie la séquence dans laquelle les instructions sont exécutées.
Commençons avec une structure de contrôle très commune, l'instruction if
. Avec l' instruction if
, vous pouvez exécuter certaines séquences de code de manière conditionnelle.
if <condition> { instruction 1 .. instruction n }
Donc, si <condition>
est vraie, vous devez exécuter le bloc de code entre crochets. Si ce n'est pas le cas, alors on ne l'exécute pas.
Ce que nous montrons ci-dessus, est l'utilisation la plus simple de if
sans la clause else
qui est optionnelle.
Le flot d'exécution est modifié car l'évaluation de la condition détermine si les instructions du bloc son exécutées ou pas.
if x > 5 { //On affiche "Yup" seulement si la valeur de x est supérieure à 5 fmt.Printf("Yup") }
Et si la condition est fausse, on ignore complètement le bloc d'instructions. Cette exemple d'utilisation de if
est tout à fait classique.
Vous pourriez également avoir une clause : else
qui exécuterait tout ce qui se trouve dans le prochain bloc. Nous n'en avons pas inclus dans l'exemple, mais il s'agit d'une extension classique que l'on retrouve dans de nombreux langages.
Il s'agit d'une autre forme d'instruction de contrôle du flot d'exécution. Comme le nom l'indique les boucles permettent de reprendre des séquences d'instructions, de les faire boucler, jusqu'à ce qu'une certaine condition soit remplie.
Les boucles modifient également le flot d'exécution, ce sont aussi des structures de contrôle. Elles sont extrêmement courantes en programmation. Elles itèrent donc simplement sur un bloc de code, jusqu'a remplir la condition de fin de boucle.
Il existe plusieurs formes de déclarations, examinons en une ici avec la boucle for
.
for <init>; <condition>; <udate> { instruction 1 ... instruction n }
Probablement une des formes les plus rependues. La syntaxe est identique en C et dans beaucoup d'autre langages. Si vous regardez ce mot clé for
, juste après, il y a trois déclarations (séparées par les ;
).
<init>
;<condition>
;<update>
.Il y a une condition, et il y a la mise à jour, séparées par des points-virgules. L'initialisation est donc exécutée une fois au début de la boucle. Ainsi, la première fois que vous entrez dans la boucle for, elle exécute cette instruction.
Ensuite, le bloc suivant contient la condition qui est vérifié à chaque itération. Ainsi, au début de chaque itération, cette condition est vérifiée : il s'agit d'une expression booléenne. Si cette condition est vraie, elle exécute toutes les instructions de la boucle. Sinon, la boucle est terminée l'exécution reprend après le code de la boucle.
Cette condition est donc la condition de fin d'emploi. Il détermine à quel moment vous arrêtez d'exécuter cette boucle. car dès que cette condition n'est pas vraie, vous sautez la boucle et vous avez terminé.
Le troisième bloc est l'expression de mise à jour. Elle est exécutée à la fin de chaque itération, et elle est utilisée pour actualiser un état, une variable agissant sur la condition de sortie de la boucle.
Une façon très courante d'utiliser la boucle “for” est d'avoir une variable d'index i
.
for i := 0; i < 10; i++ { // Cette instruction seront rejouée 10 fois fmt.Printf("Hello") }
La boucle commence en initialisant i à 0, ici on souhaite itérer 10 fois un bloc d'instruction. La condition serait continuer tant que i est inférieur à 10 on écrit i < 10
et à chaque tour de boucle on ajoute 1 à la valeur de i ce qui se traduit par i++
. Ainsi cet valeur d'index, cet état est mis à jour à chaque tour de boucle puis réévalué.
La mise à jour de cet état est important à moins que vous ne souhaitiez obtenir une boucle infinie. Car si la condition est toujours vraie, vous ne quittez jamais la boucle. Il faut donc en général s'assurer que les mises à jour de l'état de l'index finissent par rendre la condition fausse.
Voici donc quelques formes de boucles for
, ce sont les trois formes les plus courantes de boucles for
.
for i := 0; i<10; i++ { fmt.Printf("hi ") }
La première nous avons déjà vue. Vous avez l'initialisation, vous avez la condition, puis la mise à jour.
i = 0 for i<10 { fmt.Printf("hi ") i++ }
Dasn cet exemple, si vous regardez le mot clé for
, il n'y a que la vérification de condition après celui-ci. Aucune initialisation, aucune mise à jour : elles sont facultatives. Ce que nous avons fait ici pour la rendre équivalente à la boucle for
précédente, nous avons dû placer l'initialisation avant la boucle for (c'est une autre façon de procéder) et la mise à jour est désormais intégrée dans le bloc de la boucle.
C'est une autre façon de définir une boucle for
, qui ressemble à une boucle while
présente dans d'autre langages.
La dernière forme ci-dessous n'est qu'une boucle infinie.
for { Printf("hi ") }
Il n'y a rien après la boucle for, c'est juste une boucle infinie, ce qui n'est généralement pas ce que nous allons faire. Vous le faites peut-être dans un système embarqué, mais ce n'est pas courant de le faire dans un programme normal. En général, vous ne voulez pas une boucle infinie.
Une autre instruction de contrôle est switch
. On associe les mots clés switch
et case
pour définir une instruction if
multidirectionnelle (Si, sinon si, sinon si)
Un switch
, permet de définir un ensemble de cas et de n'en sélectionner qu'un seul à exécuter.
switch
peut donc contenir une variable à vérifier : x
par exemple;case
est associé à une valeur constante à laquelle x
est comparé. S'il y a correspondance sur un case, seul ce bloc d'instruction est exécuté.Mais vous pouvez le définir par défaut, donc s'il échoue, il finira par exécuter quelque chose.
Ci dessous une forme typique d'instruction switch
- case
:
switch x { case 1: fmt.Printf("case 1") case 2: fmt.Printf("case 2") default: fmt.Printf("no case") }
Notez, si vous êtes habitué à C, que l'exécution du case interrompt automatiquement le switch (En C, les blocs case
peuvent s’enchaîner si l'instruction break
est omise.
En GO, on sort automatiquement de la structure switch
lorsque le case est exécuté, ce qui est une très bonne chose.