00
:
00
:
00
:
00
Corso SEO AI - Usa SEOEMAIL al checkout per il 30% di sconto

Goto in Go

L’istruzione goto in Go permette di saltare incondizionatamente a un’etichetta all’interno della stessa funzione. È una funzionalità presente ma raramente utilizzata nel codice Go idiomatico.

Sintassi Base

func main() {
    fmt.Println("Inizio")
    goto fine
    fmt.Println("Questo non viene eseguito")
fine:
    fmt.Println("Fine")
}
// Output:
// Inizio
// Fine

Dichiarazione di Etichette

Le etichette sono identificatori seguiti da due punti (:):

func esempio() {
    i := 0
ripeti:
    if i < 5 {
        fmt.Println(i)
        i++
        goto ripeti
    }
}

Restrizioni

Go impone restrizioni importanti su goto per garantire la sicurezza del codice:

Non può saltare oltre dichiarazioni di variabili

// ERRORE: goto salta oltre la dichiarazione di x
goto dopo
x := 10
dopo:
    fmt.Println("dopo")

Non può entrare in un blocco dall’esterno

// ERRORE: non può saltare dentro un blocco if/for
goto dentro
if true {
dentro:
    fmt.Println("dentro")
}

Deve rimanere nella stessa funzione

Non è possibile usare goto per saltare tra funzioni diverse.

Casi d’Uso Legittimi

Uscita da Loop Annidati

Questo è il caso più comune e accettato:

func cercaMatrice(matrice [][]int, obiettivo int) (int, int) {
    for i, riga := range matrice {
        for j, valore := range riga {
            if valore == obiettivo {
                goto trovato
            }
        }
    }
    return -1, -1

trovato:
    return i, j
}

Tuttavia, in Go è preferibile usare etichette con break:

func cercaMatrice(matrice [][]int, obiettivo int) (int, int) {
esterno:
    for i, riga := range matrice {
        for j, valore := range riga {
            if valore == obiettivo {
                break esterno
            }
        }
    }
}

Pattern di Cleanup

func elabora() error {
    risorsa1, err := apriRisorsa1()
    if err != nil {
        goto cleanup
    }

    risorsa2, err := apriRisorsa2()
    if err != nil {
        goto cleanup1
    }

    return nil

cleanup1:
    risorsa1.Chiudi()
cleanup:
    return err
}

Nota: In Go idiomatico, questo pattern è meglio gestito con defer.

Perché Evitare goto

  • Rende il flusso del codice difficile da seguire
  • Go offre alternative migliori: break con etichette, defer, funzioni
  • Il codice con goto è più difficile da mantenere e testare

Conclusione

Sebbene goto sia disponibile in Go, il suo uso è fortemente sconsigliato nella maggior parte dei casi. Go fornisce alternative più chiare come break e continue con etichette, defer per il cleanup e funzioni per organizzare il codice. Usa goto solo quando le alternative risultano significativamente più complesse.