Parametri delle Funzioni in Go
La gestione dei parametri nelle funzioni Go e un argomento fondamentale per scrivere codice efficiente e corretto. Go utilizza il passaggio per valore come meccanismo predefinito, ma offre i puntatori per ottenere il passaggio per riferimento. Inoltre, i parametri variadici permettono di gestire un numero variabile di argomenti. In questa guida esploreremo tutti questi aspetti.
Passaggio per Valore
In Go, tutti i parametri vengono passati per valore. Questo significa che la funzione riceve una copia del valore originale. Le modifiche al parametro all’interno della funzione non influenzano la variabile originale.
package main
import "fmt"
func raddoppia(n int) {
n = n * 2
fmt.Println("Dentro la funzione:", n)
}
func main() {
valore := 10
raddoppia(valore)
fmt.Println("Fuori dalla funzione:", valore)
}
Output:
Dentro la funzione: 20
Fuori dalla funzione: 10
La variabile valore resta invariata perche la funzione raddoppia ha lavorato su una copia.
Passaggio per Riferimento con Puntatori
Per modificare il valore originale, si passa un puntatore alla variabile. Il puntatore contiene l’indirizzo di memoria della variabile, permettendo alla funzione di modificarla direttamente.
package main
import "fmt"
func raddoppia(n *int) {
*n = *n * 2
}
func main() {
valore := 10
raddoppia(&valore)
fmt.Println("Dopo raddoppia:", valore) // 20
}
*intindica che il parametro e un puntatore a un intero&valorepassa l’indirizzo di memoria della variabile*ndereferenzia il puntatore per accedere e modificare il valore
Quando Usare i Puntatori come Parametri
I puntatori nei parametri sono utili in diverse situazioni:
// 1. Quando si vuole modificare il valore originale
func incrementa(contatore *int) {
*contatore++
}
// 2. Per evitare copie di strutture grandi
type DatiPesanti struct {
Buffer [1024 * 1024]byte
Nome string
}
func elabora(dati *DatiPesanti) {
fmt.Println("Elaborazione di:", dati.Nome)
}
// 3. Per restituire errori modificando parametri
func leggiConfigurazione(percorso string, config *Configurazione) error {
// Popola config leggendo dal file
return nil
}
Parametri Variadici
I parametri variadici permettono a una funzione di accettare un numero variabile di argomenti dello stesso tipo. Si dichiarano con ... prima del tipo.
package main
import "fmt"
func somma(numeri ...int) int {
totale := 0
for _, n := range numeri {
totale += n
}
return totale
}
func main() {
fmt.Println(somma(1, 2, 3)) // 6
fmt.Println(somma(10, 20, 30, 40)) // 100
fmt.Println(somma()) // 0
}
All’interno della funzione, il parametro variadico e una slice. Nell’esempio, numeri e di tipo []int.
Passare una Slice a un Parametro Variadico
Per passare una slice esistente a una funzione variadica, si usa l’operatore ... dopo la slice.
valori := []int{5, 10, 15, 20}
risultato := somma(valori...) // Espande la slice come argomenti
fmt.Println(risultato) // 50
Parametri Variadici con Altri Parametri
Il parametro variadico deve sempre essere l’ultimo nella lista dei parametri.
func stampaFormattata(prefisso string, valori ...int) {
fmt.Print(prefisso, ": ")
for i, v := range valori {
if i > 0 {
fmt.Print(", ")
}
fmt.Print(v)
}
fmt.Println()
}
func main() {
stampaFormattata("Numeri pari", 2, 4, 6, 8)
stampaFormattata("Numeri primi", 2, 3, 5, 7, 11)
}
Il Blank Identifier per i Ritorni Non Utilizzati
Quando una funzione restituisce piu valori e non tutti sono necessari, si usa il blank identifier _ per ignorare quelli superflui.
package main
import (
"fmt"
"os"
)
func main() {
// os.Open restituisce (*File, error)
// Se non ci interessa il file, usiamo _
_, err := os.Open("file_inesistente.txt")
if err != nil {
fmt.Println("Errore:", err)
}
// Se non ci interessa l'errore (sconsigliato in produzione)
file, _ := os.Create("output.txt")
defer file.Close()
}
Il blank identifier e necessario perche Go non permette di dichiarare variabili inutilizzate: il compilatore genera un errore.
Esempio Pratico: Funzione con Parametri Misti
Vediamo un esempio completo che combina diversi tipi di parametri.
package main
import "fmt"
func calcolaStatistiche(nome string, valori ...float64) (media float64, minimo float64, massimo float64) {
if len(valori) == 0 {
return 0, 0, 0
}
minimo = valori[0]
massimo = valori[0]
somma := 0.0
for _, v := range valori {
somma += v
if v < minimo {
minimo = v
}
if v > massimo {
massimo = v
}
}
media = somma / float64(len(valori))
fmt.Printf("Statistiche per %s:\n", nome)
return
}
func main() {
med, min, max := calcolaStatistiche("Temperature", 22.5, 18.3, 30.1, 15.7, 25.0)
fmt.Printf("Media: %.1f, Min: %.1f, Max: %.1f\n", med, min, max)
}
Conclusione
Go offre un sistema di parametri chiaro e prevedibile. Il passaggio per valore e il default sicuro, mentre i puntatori danno la flessibilita del passaggio per riferimento quando necessario. I parametri variadici rendono le funzioni flessibili e il blank identifier risolve elegantemente il problema dei valori di ritorno non utilizzati. Comprendere questi meccanismi e essenziale per scrivere codice Go idiomatico.