Alt du behøver at vide om pakker i Go

Pakkeinitialisering

Når vi kører et Go-program, følger Go-kompileren en bestemt rækkefølge for udførelse af pakker, filer i en pakke og variabeldeklaration i disse filer.

Pakkeområde

Et område er et område i en kodeblok, hvor en defineret variabel er tilgængelig. Et pakkeområde er et område i en pakke, hvor en deklareret variabel er tilgængelig fra en pakke (på tværs af alle filerne i pakken). Dette område er den øverste blok i enhver fil i pakken.

Se på go run-kommandoen. Denne gang har vi i stedet for at udføre én fil et glob-mønster til at inkludere alle filerne i app-pakken til udførelse.

Go er smart nok til at finde ud af et indgangspunkt for programmet, som er entry.go, fordi det har main-funktionen. Vi kan også bruge en kommando som nedenfor (rækkefølgen af filnavne er ligegyldig).

go run src/app/version.go src/app/entry.go

💡 Du kan også bruge kommandoen go run app, som gør det samme, og det er en bedre fremgangsmåde til at udføre en pakke. Kommandoen go install eller go build kræver et pakkenavn, som omfatter alle filer i en pakke, så vi behøver ikke at angive dem som ovenfor.

For at vende tilbage til vores hovedproblem kan vi bruge variabel version, der er erklæret i filen version.go, hvor som helst i pakken, selv om den ikke er eksporteret (som Version), fordi den er erklæret i pakkeområdet.

Hvis version-variablen ville være blevet erklæret inde i en funktion, ville den ikke have været i pakkeområdet, og ovenstående program ville ikke kunne kompileres.

Det er ikke tilladt at omdeklarere en global variabel med samme navn i samme pakke. Når version variablen først er deklareret, kan den derfor ikke omdeklareres i pakkeområdet. Men du kan frit re-deklarere andre steder.

Variabelinitialisering

Når en variabel a afhænger af en anden variabel b, skal b defineres på forhånd, ellers vil programmet ikke kunne kompileres. Go følger denne regel inde i funktioner.

Men når disse variabler er defineret i pakkeområdet, er de deklareret i initialiseringscyklusser. Lad os se på det enkle eksempel nedenfor:

I ovenstående eksempel er først c deklareret, fordi dens værdi allerede er deklareret. I den senere initialiseringscyklus deklareres b, fordi den afhænger af c, og værdien af c er allerede deklareret. I den sidste initialiseringscyklus erklæres a og tildeles værdien af b. Go kan håndtere komplekse initialiseringscyklusser som nedenfor:

I ovenstående eksempel vil først c blive erklæret og derefter b, da dens værdi afhænger af c, og til sidst a, da dens værdi afhænger af b. Du bør undgå enhver initialiseringssløjfe som nedenfor, hvor initialiseringen bliver til en rekursiv sløjfe.

Et andet eksempel på pakkeomfang ville være, at have en funktion f i en separat fil, som refererer til variabel c fra hovedfilen.

Init-funktion

Lignende main funktion, init funktionen kaldes af Go, når en pakke initialiseres. Den tager ikke imod nogen argumenter og returnerer ikke nogen værdi.

init-funktionen er implicit deklareret af Go, og derfor kan du ikke referere til den fra noget sted (eller kalde den som init()). Du kan have flere init-funktioner i en fil eller en pakke. Rækkefølgen af udførelsen af init-funktioner i en fil vil være i overensstemmelse med rækkefølgen af deres forekomst.

Du kan have init-funktioner hvor som helst i en pakke. Disse init-funktioner kaldes i leksikalsk filnavneorden (alfabetisk orden).

Når alleinit-funktioner er udført, kaldes main-funktionen. Derfor er init-funktionens hovedopgave at initialisere globale variabler, som ikke kan initialiseres i den globale kontekst. For eksempel initialisering af et array.

Da for-syntaksen ikke er gyldig i pakkeområdet, kan vi initialisere arrayet integers af størrelse 10 ved hjælp af for-løkken inde i init-funktionen.

Pakkealias

Når du importerer en pakke, Go opretter du en variabel ved hjælp af pakkedeklarationen for pakken. Hvis du importerer flere pakker med samme navn, vil det føre til en konflikt.

// greet/parent.go
package greetvar Message = "Hey there. I am parent."// greet/greet/child.go
package greetvar Message = "Hey there. I am child."

Derfor bruger vi pakkealias. Vi angiver et variabelnavn mellem nøgleordet import og pakkenavnet, som bliver den nye variabel til at referere til pakken.

I ovenstående eksempel refereres -pakken nu af child-variablen. Hvis du bemærker det, har vi givet greet pakke et alias med en understregning.

Understregning er et særligt tegn i Go, som fungerer som null container. Da vi importerer greet-pakken, men ikke bruger den, vil Go-compileren klage over det. For at undgå det gemmer vi referencen til den pågældende pakke i _, og Go compiler vil simpelthen ignorere den.

Afgivelse af en pakke med en understregning, som tilsyneladende ikke gør noget, er nogle gange ganske nyttigt, når du ønsker at initialisere en pakke, men ikke bruge den.

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

Den vigtigste ting at huske er, at en importeret pakke kun initialiseres én gang pr. pakke. Derfor, hvis du har flere import-erklæringer i en pakke, vil en importeret pakke kun blive initialiseret én gang i løbet af hovedpakkeudførelsens levetid.