Vše, co potřebujete vědět o balíčcích v Go

Inicializace balíčků

Při spouštění programu v jazyce Go dodržuje překladač Go určité pořadí provádění balíčků, souborů v balíčku a deklarací proměnných v těchto souborech.

Obsah balíčku

Obsah je oblast v bloku kódu, kde je přístupná definovaná proměnná. Obor balíčku je oblast v balíčku, kde je deklarovaná proměnná přístupná z balíčku (napříč všemi soubory v balíčku). Tato oblast je nejvyšším blokem libovolného souboru v balíčku.

Podívejte se na příkaz go run. Tentokrát místo spuštění jednoho souboru máme glob vzor, který zahrnuje všechny soubory uvnitř balíčku app ke spuštění.

Go je dost chytrý na to, aby zjistil vstupní bod aplikace, kterým je entry.go, protože má funkci main. Můžeme také použít příkaz jako níže (na pořadí názvů souborů nezáleží).

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

💡 Můžete také použít příkaz go run app, který dělá totéž a je to lepší přístup ke spuštění balíčku. Příkaz go install nebo go build vyžaduje název balíčku, který zahrnuje všechny soubory uvnitř balíčku, takže je nemusíme specifikovat jako výše.

Vrátíme-li se k našemu hlavnímu problému, můžeme proměnnou version deklarovanou v souboru version.go použít odkudkoli z balíčku, i když není exportovaná (jako Version), protože je deklarovaná v rozsahu balíčku.

Pokud by byla proměnná version deklarována uvnitř funkce, nebyla by v oboru balíčku a výše uvedený program by se nepodařilo zkompilovat.

Globální proměnnou se stejným jménem nesmíte ve stejném balíčku deklarovat znovu. Proto jakmile je jednou version proměnná deklarována, nelze ji v oboru balíčku deklarovat znovu. Můžete ji však znovu deklarovat jinde.

Inicializace proměnných

Když proměnná a závisí na jiné proměnné b, měla by být b definována předem, jinak se program nezkompiluje. Go se tímto pravidlem řídí uvnitř funkcí.

Pokud jsou ale tyto proměnné definovány v oboru balíčku, deklarují se v inicializačních cyklech. Podívejme se na jednoduchý příklad níže:

V uvedeném příkladu je nejprve deklarována c, protože její hodnota je již deklarována. V pozdějším inicializačním cyklu se deklaruje b, protože závisí na c a hodnota c je již deklarována. V posledním inicializačním cyklu je deklarována hodnota a, která je přiřazena hodnotě b. Go si poradí se složitými inicializačními cykly, jak je uvedeno níže.

V uvedeném příkladu se nejprve deklaruje c a poté b, protože jeho hodnota závisí na c, a nakonec a, protože jeho hodnota závisí na b. Měli byste se vyhnout jakékoli inicializační smyčce jako níže, kdy se inicializace dostane do rekurzivní smyčky.

Dalším příkladem rozsahu balíčku by bylo, mít funkci f v samostatném souboru, která odkazuje na proměnnou c z hlavního souboru.

Init funkce

Podobně jako funkce main, init je funkce volána Go při inicializaci balíčku. Nepřijímá žádné argumenty a nevrací žádnou hodnotu.

Funkce init je Go implicitně deklarována, proto se na ni nelze odnikud odkazovat (nebo ji volat jako init()). V souboru nebo balíčku můžete mít více funkcí init. Pořadí provádění funkce init v souboru bude odpovídat pořadí jejich výskytu.

Funkci init můžete mít kdekoli v balíčku. Tyto funkce init jsou volány v lexikálním pořadí názvů souborů (abecedně).

Po provedení všech funkcí init je volána funkce main. Hlavním úkolem funkce init je tedy inicializovat globální proměnné, které nelze inicializovat v globálním kontextu. Například inicializace pole.

Protože syntaxe for není platná v oboru balíčku, můžeme inicializovat pole integers o velikosti 10 pomocí cyklu for uvnitř funkce init.

Paket alias

Pokud importujete balíček, Go vytvoří proměnnou pomocí deklarace balíčku tohoto balíčku. Pokud importujete více balíčků se stejným názvem, povede to ke konfliktu.

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

Proto používáme alias balíčku. Mezi klíčové slovo import a název balíčku uvedeme název proměnné, která se stane novou proměnnou pro odkaz na balíček.

V uvedeném příkladu se nyní na balíček greet/greet odkazuje proměnná child. Pokud jste si všimli, balíček greet jsme aliasovali podtržítkem.

Podtržítko je v jazyce Go speciální znak, který funguje jako kontejner null. Protože balík greet importujeme, ale nepoužíváme ho, kompilátor Go si na to bude stěžovat. Abychom se tomu vyhnuli, uložíme odkaz na tento balíček do _ a překladač Go jej bude jednoduše ignorovat.

Odkazování balíčku podtržítkem, které zdánlivě nic nedělá, je někdy docela užitečné, když chceme balíček inicializovat, ale nepoužívat jej.

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

Hlavní věc, kterou je třeba si zapamatovat, je, že importovaný balíček se v každém balíčku inicializuje pouze jednou. Pokud tedy máte v balíčku více příkazů import, bude importovaný balíček inicializován pouze jednou za celou dobu provádění hlavního balíčku.