Tout ce que vous devez savoir sur les paquets en Go

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 commande go install ou go 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 versionavait é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.

Un autre exemple de portée de paquetage serait, avoir une fonction f dans un fichier séparé qui fait référence à la variable c du fichier principal.

Fonction d’init

Comme la fonction main, init la fonction est appelée par Go lorsqu’un paquetage est initialisé. Elle ne prend aucun argument et ne retourne aucune valeur.

La fonction init est implicitement déclarée par Go, donc vous ne pouvez pas la référencer de n’importe où (ou l’appeler comme init()). Vous pouvez avoir plusieurs fonctions init dans un fichier ou un paquet. L’ordre d’exécution de la fonction init dans un fichier sera en fonction de l’ordre de leurs apparitions.

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.