Pacchetti in Go
In Go, i pacchetti (packages) sono il meccanismo fondamentale per organizzare e riutilizzare il codice. Ogni file Go appartiene a un pacchetto, e ogni programma Go e composto da uno o piu pacchetti.
Cos’e un Pacchetto
Un pacchetto e una collezione di file Go nella stessa directory che condividono la stessa dichiarazione package. I pacchetti permettono di:
- Organizzare il codice in unita logiche
- Controllare la visibilita dei nomi (esportazione)
- Riutilizzare il codice tra progetti diversi
Dichiarazione del Pacchetto
Ogni file Go inizia con una dichiarazione di pacchetto:
package main // pacchetto eseguibile
// oppure
package matematica // pacchetto libreria
Il pacchetto main e speciale: indica un programma eseguibile e deve contenere una funzione main().
Nomi Esportati vs Non Esportati
In Go, la visibilita e determinata dalla lettera iniziale del nome:
- Maiuscola = esportato (visibile dall’esterno del pacchetto)
- Minuscola = non esportato (privato al pacchetto)
package utente
// Esportato: accessibile da altri pacchetti
type Profilo struct {
Nome string // esportato
Email string // esportato
eta int // non esportato
}
// Esportato
func NuovoProfilo(nome, email string, eta int) *Profilo {
return &Profilo{Nome: nome, Email: email, eta: eta}
}
// Non esportato: accessibile solo all'interno del pacchetto 'utente'
func validaEmail(email string) bool {
return len(email) > 0
}
Da un altro pacchetto:
package main
import "mioprogetto/utente"
func main() {
p := utente.NuovoProfilo("Marco", "marco@email.it", 30)
fmt.Println(p.Nome) // OK: Nome e esportato
// fmt.Println(p.eta) // ERRORE: eta non e esportato
// utente.validaEmail("test") // ERRORE: validaEmail non e esportato
}
Importare Pacchetti
I pacchetti si importano con la parola chiave import:
// Importazione singola
import "fmt"
// Importazione multipla (forma raggruppata)
import (
"fmt"
"math"
"strings"
"mioprogetto/utente" // pacchetto locale
)
Alias per i Pacchetti
E possibile assegnare un alias a un pacchetto importato:
import (
f "fmt" // alias 'f' per fmt
str "strings" // alias 'str' per strings
_ "database/sql/driver" // import per effetti collaterali (init)
. "math" // import diretto (sconsigliato)
)
func main() {
f.Println("Ciao") // usa l'alias
str.ToUpper("go") // usa l'alias
}
L’underscore _ importa il pacchetto solo per eseguire la sua funzione init(), senza usarne i nomi.
Inizializzazione del Pacchetto
Variabili a Livello di Pacchetto
Le variabili a livello di pacchetto vengono inizializzate prima della funzione main():
package config
var (
NomeApp = "MiaApp"
Versione = "1.0.0"
MaxUtenti = 100
)
La Funzione init()
Ogni file Go puo contenere una o piu funzioni init() che vengono eseguite automaticamente all’inizializzazione del pacchetto:
package database
import (
"fmt"
"os"
)
var connessione string
func init() {
connessione = os.Getenv("DATABASE_URL")
if connessione == "" {
connessione = "localhost:5432"
}
fmt.Println("Database configurato:", connessione)
}
L’ordine di inizializzazione e:
- Variabili a livello di pacchetto
- Funzioni
init()nell’ordine in cui appaiono nel file - Se ci sono piu file, in ordine alfabetico dei nomi dei file
Nota: non e possibile chiamare init() esplicitamente. Viene invocata automaticamente dal runtime.
Panoramica della Libreria Standard
Go ha una libreria standard ricca e ben progettata. Ecco i pacchetti piu importanti:
import (
"fmt" // formattazione e stampa
"os" // interfaccia con il sistema operativo
"io" // interfacce per I/O
"strings" // manipolazione stringhe
"strconv" // conversioni stringa <-> numeri
"math" // funzioni matematiche
"sort" // algoritmi di ordinamento
"net/http" // client e server HTTP
"encoding/json" // codifica/decodifica JSON
"time" // gestione del tempo
"context" // contesto per cancellazione e timeout
"sync" // primitive di sincronizzazione
"errors" // gestione errori
"log" // logging
"testing" // framework di test
)
Creare i Propri Pacchetti
Ecco come organizzare un progetto con pacchetti personalizzati:
Struttura del progetto:
mioprogetto/
go.mod
main.go
matematica/
operazioni.go
costanti.go
utilita/
stringhe.go
File matematica/operazioni.go:
package matematica
// Somma restituisce la somma di due interi
func Somma(a, b int) int {
return a + b
}
// Media calcola la media di uno slice di float64
func Media(numeri []float64) float64 {
if len(numeri) == 0 {
return 0
}
somma := 0.0
for _, n := range numeri {
somma += n
}
return somma / float64(len(numeri))
}
File matematica/costanti.go:
package matematica
const (
Pi = 3.14159265358979
E = 2.71828182845904
)
File main.go:
package main
import (
"fmt"
"mioprogetto/matematica"
)
func main() {
risultato := matematica.Somma(3, 7)
fmt.Println("Somma:", risultato)
media := matematica.Media([]float64{10, 20, 30})
fmt.Println("Media:", media)
fmt.Println("Pi greco:", matematica.Pi)
}
Convenzioni sui Nomi dei Pacchetti
Go ha convenzioni chiare per i nomi dei pacchetti:
- Minuscolo: i nomi dei pacchetti sono sempre in minuscolo (
strings, nonStrings) - Parola singola: preferire nomi brevi e descrittivi (
http,json,time) - No underscore o camelCase: usare
httputil, nonhttp_utilohttpUtil - Non ripetere il nome del pacchetto nei nomi esportati:
http.Server, nonhttp.HTTPServer
Conclusione
I pacchetti sono il fondamento dell’organizzazione del codice in Go. Comprendere come creare pacchetti, controllare la visibilita con le lettere maiuscole e minuscole, e sfruttare la funzione init() e la libreria standard e essenziale per scrivere codice Go ben strutturato e manutenibile. La semplicita del sistema di pacchetti di Go e uno dei suoi punti di forza principali.