HowtoGo
Home / Basics / Goto
Basics

Goto

Terms Label

goto jumps to a labeled statement in the same function. The compiler blocks two shapes of jump: into a block the code wasn't already inside, and past a variable declaration that's still in scope at the label.

A label like retry: marks a target. goto retry jumps straight to it, running the same way a for loop would with the same condition.

attempts := 0
retry:
attempts++
fmt.Println("attempt", attempts)
if attempts < 3 {
    goto retry
}
fmt.Println("gave up after", attempts)

Most jumps a goto could make read more clearly as a labeled break or continue. The case where goto earns its place: bailing out of a loop straight to a shared return path once a value turns up, skipping every check that follows it.

func firstPositive(nums []int) (int, bool) {
    var result int
    for _, n := range nums {
        if n <= 0 {
            continue
        }
        result = n
        goto found
    }
    return 0, false

found:
    return result, true
}

result is declared before the found label, not after. Declaring it past the label would jump over a variable still in scope at that point, which the compiler rejects.

package main

import "fmt"

func firstPositive(nums []int) (int, bool) {
    var result int
    for _, n := range nums {
        if n <= 0 {
            continue
        }
        result = n
        goto found
    }
    return 0, false

found:
    return result, true
}

func main() {
    n, ok := firstPositive([]int{-3, -1, 0, 4, 9})
    fmt.Println(n, ok)
}

The loop reaches 4, the first positive value in the slice, and jumps to found without evaluating 9.

Terminal
$ go run main.go
4 true