Initialisation des paquets
Lorsque nous exécutons un programme Go, le compilateur Go suit un certain ordre d’exécution pour les paquets, les fichiers dans un paquet et la déclaration des variables dans ces fichiers.
Package scope
Un scope est une région dans un bloc de code où une variable définie est accessible. Un scope de package est une région dans un package où une variable déclarée est accessible depuis un package (à travers tous les fichiers du package). Cette région est le bloc le plus haut de tout fichier du paquet.
Regardez la commande go run
. Cette fois, au lieu d’exécuter un fichier, nous avons un motif glob pour inclure tous les fichiers à l’intérieur du paquet app
pour l’exécution.
Go est assez intelligent pour trouver un point d’entrée de l’application qui est entry.go
parce qu’il a la fonction main
. Nous pouvons également utiliser une commande comme ci-dessous (l’ordre des noms de fichiers n’a pas d’importance).
go run src/app/version.go src/app/entry.go
💡 Vous pouvez également utiliser la commande
go run app
qui fait la même chose et c’est une meilleure approche pour exécuter un paquet. La commandego install
ougo build
nécessite un nom de paquet, qui inclut tous les fichiers à l’intérieur d’un paquet, donc nous n’avons pas à les spécifier comme ci-dessus.
Retour à notre question principale, nous pouvons utiliser la variable version
déclarée dans le fichier version.go
de n’importe où dans le paquet même si elle n’est pas exportée (comme Version
), car elle est déclarée dans la portée du paquet.
Si la variable version
avait été déclarée à l’intérieur d’une fonction, elle n’aurait pas été dans la portée du paquet et le programme ci-dessus aurait échoué à compiler.
Vous n’êtes pas autorisé à redéclarer une variable globale avec le même nom dans le même paquet. Par conséquent, une fois que la variable version
est déclarée, elle ne peut pas être redéclarée dans la portée du paquet. Mais vous êtes libre de la redéclarer ailleurs.
Initialisation des variables
Lorsqu’une variable a
dépend d’une autre variable b
, b
doit être définie au préalable, sinon le programme ne compilera pas. Go suit cette règle à l’intérieur des fonctions.
Mais lorsque ces variables sont définies dans la portée du package, elles sont déclarées dans les cycles d’initialisation. Regardons l’exemple simple ci-dessous.
Dans l’exemple ci-dessus, d’abord c
est déclaré parce que sa valeur est déjà déclarée. Dans le cycle d’initialisation ultérieur, b
est déclaré, car il dépend de c
et la valeur de c
est déjà déclarée. Dans le cycle d’initialisation final, a
est déclaré et affecté à la valeur de b
. Go peut gérer des cycles d’initialisation complexes comme ci-dessous.
Dans l’exemple ci-dessus, d’abord c
sera déclaré et ensuite b
car sa valeur dépend de c
et enfin a
car sa valeur dépend de b
. Vous devriez éviter toute boucle d’initialisation comme ci-dessous où l’initialisation se retrouve dans une boucle récursive.
Vous pouvez avoir une fonction init
n’importe où dans le paquet. Ces fonctions init
sont appelées dans l’ordre lexical des noms de fichiers (ordre alphabétique).
Après l’exécution de toutes les fonctionsinit
, la fonction main
est appelée. Par conséquent, le travail principal de la fonction init
est d’initialiser les variables globales qui ne peuvent pas être initialisées dans le contexte global. Par exemple, l’initialisation d’un tableau.
Puisque, la syntaxe for
n’est pas valide dans la portée du paquet, nous pouvons initialiser le tableau integers
de taille 10
en utilisant la boucle for
à l’intérieur de la fonction init
.
Package alias
Lorsque vous importez un paquet, Go crée une variable en utilisant la déclaration du paquet. Si vous importez plusieurs paquets avec le même nom, cela entraînera un conflit.
// greet/parent.go
package greetvar Message = "Hey there. I am parent."// greet/greet/child.go
package greetvar Message = "Hey there. I am child."
C’est pourquoi nous utilisons l’alias de paquet. Nous indiquons un nom de variable entre le mot clé import
et le nom du paquet qui devient la nouvelle variable pour référencer le paquet.
Dans l’exemple ci-dessus, le paquet greet/greet
est maintenant référencé par la variable child
. Si vous remarquez, nous avons aliasé le paquet greet
avec un trait de soulignement.
Le trait de soulignement est un caractère spécial dans Go qui agit comme un conteneur null
. Comme nous importons le paquet greet
mais que nous ne l’utilisons pas, le compilateur Go s’en plaindra. Pour éviter cela, nous stockons la référence de ce paquet dans _
et le compilateur Go l’ignorera simplement.
Aliaser un paquet avec un underscore qui semble ne rien faire est assez utile parfois quand vous voulez initialiser un paquet mais ne pas l’utiliser.
// greet/parent.go
package greetimport "fmt"var Message = "Hey there. I am parent."func init() {
fmt.Println("greet/parent.go ==> init()")
}// greet/greet/child.go
package greetimport "fmt"var Message = "Hey there. I am child."func init() {
fmt.Println("greet/greet/child.go ==> init()")
}
La principale chose à retenir est qu’un paquet importé n’est initialisé qu’une fois par paquet. Par conséquent, si vous avez plusieurs déclarations d’importation dans un paquet, un paquet importé ne sera initialisé qu’une seule fois dans la durée de vie de l’exécution du paquet principal.