Sintassi
Struttura di un programma Go
Ogni programma Go segue una struttura ben definita. Comprendere questa struttura e fondamentale per iniziare a scrivere codice corretto.
package main
import "fmt"
func main() {
fmt.Println("Benvenuto in Go!")
}
Ogni file Go inizia con tre elementi fondamentali: la dichiarazione del pacchetto, le importazioni e le definizioni di funzioni o tipi.
Dichiarazione del pacchetto
La prima riga di ogni file Go deve essere la dichiarazione del pacchetto con la parola chiave package:
package main
Il pacchetto main ha un significato speciale: indica che il file fa parte di un programma eseguibile. Qualsiasi altro nome di pacchetto indica una libreria che puo essere importata da altri programmi.
// Una libreria per operazioni matematiche
package matematica
// Una libreria per la gestione degli utenti
package utenti
Importazioni
Dopo la dichiarazione del pacchetto, si dichiarano le importazioni con la parola chiave import. Le importazioni specificano quali pacchetti esterni vengono utilizzati nel file.
Importazione singola
import "fmt"
Importazione multipla (raggruppata)
La forma preferita e quella raggruppata con le parentesi:
import (
"fmt"
"math"
"strings"
)
Importazione con alias
Puoi assegnare un alias a un pacchetto per evitare conflitti di nome:
import (
f "fmt"
s "strings"
)
func main() {
f.Println(s.ToUpper("ciao"))
}
Importazione per effetti collaterali
A volte si importa un pacchetto solo per i suoi effetti collaterali (come la registrazione di driver), utilizzando il blank identifier:
import (
"database/sql"
_ "github.com/lib/pq" // importato solo per il side effect
)
Go genera un errore di compilazione se importi un pacchetto senza utilizzarlo. Questa regola mantiene il codice pulito.
La funzione main
La funzione main nel pacchetto main e il punto di ingresso di ogni programma Go eseguibile:
package main
import "fmt"
func main() {
fmt.Println("Il programma inizia qui")
// tutto il codice viene eseguito a partire da questa funzione
}
La funzione main non accetta parametri e non restituisce valori. Per accedere agli argomenti della riga di comando si usa il pacchetto os:
package main
import (
"fmt"
"os"
)
func main() {
argomenti := os.Args
fmt.Println("Argomenti:", argomenti)
}
Punto e virgola (semicolons)
In Go, i punti e virgola sono inseriti automaticamente dal compilatore (lexer) alla fine delle righe. Non e necessario (e non e consigliato) scriverli manualmente:
// Corretto: senza punto e virgola
fmt.Println("Ciao")
x := 10
// Tecnicamente valido ma non idiomatico
fmt.Println("Ciao");
x := 10;
L’inserimento automatico dei punti e virgola ha una conseguenza importante: la parentesi graffa di apertura { deve trovarsi sulla stessa riga della dichiarazione:
// CORRETTO
func main() {
fmt.Println("Ciao")
}
// ERRORE DI COMPILAZIONE
// func main()
// {
// fmt.Println("Ciao")
// }
Blocchi di codice con le parentesi graffe
Go utilizza le parentesi graffe {} per delimitare i blocchi di codice. Ogni funzione, istruzione condizionale, ciclo e struttura di controllo utilizza le graffe:
package main
import "fmt"
func main() {
nome := "Go"
if len(nome) > 0 {
fmt.Println("Il nome e:", nome)
} else {
fmt.Println("Nome vuoto")
}
for i := 0; i < 3; i++ {
fmt.Printf("Iterazione %d\n", i)
}
}
Sensibilita alle maiuscole (case sensitivity)
Go e un linguaggio case-sensitive, il che significa che nome, Nome e NOME sono tre identificatori diversi:
var nome string = "Mario"
var Nome string = "Luigi"
// nome e Nome sono variabili diverse
Convenzioni di denominazione
In Go, la capitalizzazione della prima lettera ha un significato fondamentale per la visibilita (exported vs unexported):
Identificatori esportati (exported)
Un identificatore che inizia con la lettera maiuscola e esportato, cioe visibile e accessibile da altri pacchetti:
package utenti
// Utente e esportato: accessibile da altri pacchetti
type Utente struct {
Nome string // campo esportato
Email string // campo esportato
}
// CreaUtente e una funzione esportata
func CreaUtente(nome, email string) Utente {
return Utente{Nome: nome, Email: email}
}
Identificatori non esportati (unexported)
Un identificatore che inizia con la lettera minuscola e visibile solo all’interno del pacchetto in cui e definito:
package utenti
// dettaglioInterno non e accessibile da altri pacchetti
type dettaglioInterno struct {
id int
}
// funzione privata al pacchetto
func validaEmail(email string) bool {
return len(email) > 0
}
Convenzioni di stile
Go segue convenzioni precise per i nomi:
// camelCase per variabili e funzioni non esportate
var nomeUtente string
func calcolaMedia() float64 { return 0.0 }
// PascalCase per tipi, funzioni e variabili esportate
type ContoCorrente struct{}
func CalcolaTotale() float64 { return 0.0 }
// Acronimi mantengono la capitalizzazione uniforme
var httpClient string // non esportato
var HTTPClient string // esportato
var userID int // non esportato
var UserID int // esportato
Lo strumento gofmt
Go include uno strumento di formattazione ufficiale chiamato gofmt che applica automaticamente lo stile standard al codice. Questo elimina i dibattiti sulla formattazione:
// Prima di gofmt (formattazione inconsistente)
// func somma(a int,b int)int{
// return a+b
// }
// Dopo gofmt (formattazione standard)
func somma(a int, b int) int {
return a + b
}
Puoi formattare un file eseguendo gofmt -w main.go oppure go fmt ./... per formattare l’intero progetto.
Conclusione
La sintassi di Go e volutamente minimalista e rigorosa. Le regole sull’inserimento automatico dei punti e virgola, la posizione delle parentesi graffe e le convenzioni di denominazione per la visibilita non sono scelte arbitrarie ma decisioni progettuali che rendono il codice Go coerente e leggibile. Familiarizzare con queste convenzioni fin dall’inizio ti aiutera a scrivere codice idiomatico e professionale.