Package initialisatie
Wanneer we een Go programma uitvoeren, volgt de Go compiler een bepaalde uitvoeringsvolgorde voor packages, bestanden in een package en variabele declaratie in die bestanden.
Package scope
Een scope is een regio in een codeblok waar een gedefinieerde variabele toegankelijk is. Een package scope is een regio binnen een package waar een gedeclareerde variabele toegankelijk is vanuit een package (over alle bestanden in de package). Dit gebied is het bovenste blok van elk bestand in het pakket.
Variabele initialisatie
Wanneer een variabele a
afhankelijk is van een andere variabele b
, moet b
van te voren worden gedefinieerd, anders zal het programma niet compileren. Go volgt deze regel binnen functies.
Maar wanneer deze variabelen worden gedefinieerd in package scope, worden ze gedeclareerd in initialisatiecycli. Laten we eens kijken naar het eenvoudige voorbeeld hieronder.
In het bovenstaande voorbeeld wordt eerst c
gedeclareerd omdat de waarde ervan al is gedeclareerd. In de volgende initialisatiecyclus wordt b
gedeclareerd, omdat deze afhankelijk is van c
en de waarde van c
al is gedeclareerd. In de laatste initialisatiecyclus wordt a
gedeclareerd en toegewezen aan de waarde van b
. Go kan omgaan met complexe initialisatiecycli zoals hieronder.
In het bovenstaande voorbeeld wordt eerst c
gedeclareerd en vervolgens b
omdat de waarde daarvan afhangt van c
en ten slotte a
omdat de waarde daarvan afhangt van b
. U moet een initialisatielus zoals hieronder vermijden, waarbij de initialisatie in een recursieve lus terechtkomt.
Een ander voorbeeld van package scope zou zijn, dat u een functie f
in een apart bestand hebt, die verwijst naar variabele c
uit het hoofdbestand.
Init functie
Zoals main
functie, init
wordt de functie door Go aangeroepen wanneer een pakket wordt geïnitialiseerd. De functie init
wordt impliciet door Go gedeclareerd, zodat u er nergens naar kunt verwijzen (of de functie kunt aanroepen zoals init()
). U kunt meerdere init
functies in een bestand of een package hebben. De volgorde waarin init
-functies in een bestand worden uitgevoerd, wordt bepaald door de volgorde waarin ze verschijnen.
U kunt init
-functies overal in het pakket hebben. Deze init
-functies worden aangeroepen in lexicale bestandsnaamvolgorde (alfabetische volgorde).
Nadat alleinit
-functies zijn uitgevoerd, wordt main
-functie aangeroepen. De belangrijkste taak van de functie init
is dus om globale variabelen te initialiseren die niet in de globale context kunnen worden geïnitialiseerd. Bijvoorbeeld de initialisatie van een array.
Omdat de syntax for
niet geldig is in package scope, kunnen we de array integers
van grootte 10
initialiseren met behulp van for
loop binnen init
functie.
Pakket alias
Wanneer u een pakket importeert, gaat u een variabele maken met behulp van de pakketdeclaratie van het pakket. Als u meerdere pakketten met dezelfde naam importeert, leidt dit tot een conflict.
// greet/parent.go
package greetvar Message = "Hey there. I am parent."// greet/greet/child.go
package greetvar Message = "Hey there. I am child."
Hierom gebruiken we package alias. Tussen het trefwoord import
en de pakketnaam plaatsen we een variabelenaam die de nieuwe variabele wordt om naar het pakket te verwijzen.
In het bovenstaande voorbeeld wordt naar het pakket greet/greet
nu verwezen door variabele child
. Zoals u ziet, hebben we greet
package gealiased met een underscore.
Underscore is een speciaal teken in Go dat fungeert als null
container. Omdat we greet
package importeren maar niet gebruiken, zal de Go compiler hierover klagen. Om dat te voorkomen, slaan we de referentie van dat pakket op in _
en Go compiler zal het gewoon negeren.
Het linken van een pakket met een underscore die niets lijkt te doen, is soms erg handig wanneer je een pakket wilt initialiseren maar niet gebruiken.
// 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()")
}
Het belangrijkste om te onthouden is dat een geïmporteerd pakket slechts eenmaal per pakket wordt geïnitialiseerd. Als je dus meerdere import-statements in een pakket hebt, wordt een geïmporteerd pakket maar één keer geïnitialiseerd tijdens de uitvoering van het hoofdpakket.