Tutto quello che c’è da sapere sui pacchetti in Go

Inizializzazione dei pacchetti

Quando eseguiamo un programma Go, il compilatore Go segue un certo ordine di esecuzione per i pacchetti, i file in un pacchetto e la dichiarazione delle variabili in quei file.

Scampo del pacchetto

Uno scopo è una regione in un blocco di codice dove una variabile definita è accessibile. Uno scope di pacchetto è una regione all’interno di un pacchetto dove una variabile dichiarata è accessibile dall’interno di un pacchetto (attraverso tutti i file del pacchetto). Questa regione è il blocco più in alto di qualsiasi file nel pacchetto.

Guarda il comando go run. Questa volta, invece di eseguire un file, abbiamo un pattern glob per includere tutti i file all’interno del pacchetto app per l’esecuzione.

Go è abbastanza intelligente da capire un punto di ingresso dell’applicazione che è entry.go perché ha la funzione main. Possiamo anche usare un comando come qui sotto (l’ordine dei nomi dei file non ha importanza).

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

💡 Puoi anche usare il comando go run app che fa la stessa cosa e questo è un approccio migliore per eseguire un pacchetto. Il comando go install o go build richiede un nome di pacchetto, che include tutti i file all’interno di un pacchetto, quindi non dobbiamo specificarli come sopra.

Tornando al nostro problema principale, possiamo usare la variabile version dichiarata nel file version.go da qualsiasi punto del pacchetto anche se non è esportata (come Version), perché è dichiarata nello scope del pacchetto.

Se la variabile version fosse stata dichiarata all’interno di una funzione, non sarebbe stata nello scope del package e il programma di cui sopra non sarebbe riuscito a compilare.

Non è permesso ridichiarare una variabile globale con lo stesso nome nello stesso package. Quindi, una volta dichiarata la variabile version, non può essere ridichiarata nello scope del pacchetto. Ma sei libero di ridichiararla altrove.

Inizializzazione delle variabili

Quando una variabile a dipende da un’altra variabile b, b deve essere definita prima, altrimenti il programma non verrà compilato. Go segue questa regola all’interno delle funzioni.

Ma quando queste variabili sono definite nel package scope, sono dichiarate nei cicli di inizializzazione. Diamo un’occhiata al semplice esempio qui sotto.

Nell’esempio precedente, prima c è dichiarato perché il suo valore è già dichiarato. Nel ciclo di inizializzazione successivo, b è dichiarato, perché dipende da c e il valore di c è già dichiarato. Nel ciclo di inizializzazione finale, a è dichiarato e assegnato al valore di b. Go può gestire cicli di inizializzazione complessi come qui sotto.

Nell’esempio sopra, prima c sarà dichiarato e poi b come il suo valore dipende da c e infine a come il suo valore dipende da b. Dovresti evitare qualsiasi ciclo di inizializzazione come sotto, dove l’inizializzazione entra in un ciclo ricorsivo.

Un altro esempio di scopo del pacchetto sarebbe, avere una funzione f in un file separato che fa riferimento alla variabile c dal file principale.

Funzione Init

Come la funzione main, initviene chiamata da Go quando un pacchetto viene inizializzato. Non prende nessun argomento e non restituisce nessun valore.

La funzione init è dichiarata implicitamente da Go, quindi non si può fare riferimento ad essa da nessuna parte (o chiamarla come init()). Puoi avere più funzioni init in un file o in un pacchetto. L’ordine di esecuzione delle funzioni init in un file sarà secondo l’ordine della loro apparizione.

È possibile avere funzioni init in qualsiasi punto del pacchetto. Queste funzioni init sono chiamate in ordine lessicale di nome del file (ordine alfabetico).

Dopo che tutte le funzioni init sono state eseguite, viene chiamata la funzione main. Quindi, il compito principale della funzione init è di inizializzare le variabili globali che non possono essere inizializzate nel contesto globale. Per esempio, l’inizializzazione di un array.

Siccome, la sintassi for non è valida nello scopo del pacchetto, possiamo inizializzare l’array integers di dimensione 10 usando for loop all’interno della funzione init.

Alias di pacchetto

Quando importate un pacchetto, andate a creare una variabile usando la dichiarazione del pacchetto. Se stai importando più pacchetti con lo stesso nome, questo porterà ad un conflitto.

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

Quindi, usiamo gli alias di pacchetto. Indichiamo un nome di variabile tra la parola chiave import e il nome del pacchetto che diventa la nuova variabile di riferimento al pacchetto.

Nell’esempio precedente, il pacchetto greet/greet ora è referenziato dalla variabile child. Se ci fai caso, abbiamo aggiunto un underscore al pacchetto greet.

Underscore è un carattere speciale in Go che funge da contenitore null. Poiché stiamo importando il pacchetto greet ma non lo usiamo, il compilatore Go si lamenterà di questo. Per evitarlo, stiamo memorizzando il riferimento a quel pacchetto in _ e il compilatore Go semplicemente lo ignorerà.

L’eliminazione di un pacchetto con un underscore che sembra non fare nulla è abbastanza utile a volte quando si vuole inizializzare un pacchetto ma non usarlo.

// 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 cosa principale da ricordare è che un pacchetto importato viene inizializzato solo una volta per pacchetto. Quindi se si hanno più dichiarazioni di importazione in un pacchetto, un pacchetto importato verrà inizializzato solo una volta nel corso dell’esecuzione del pacchetto principale.