ZetCode

Golang goto 关键字

最后修改于 2025 年 5 月 7 日

本教程将解释如何在 Go 中使用 goto 关键字。我们将通过实际使用 goto 语句的示例来涵盖跳转控制基础。

goto 语句将控制转移到同一函数内的带标签语句。它提供了对代码其他部分的无条件跳转。

在 Go 中,goto 必须跳转到同一函数中声明的标签。它不能跳过变量声明或跳转到其他块。请谨慎使用它。

基本 goto 示例

goto 最简单的用法是跳转到同一函数中的标签。此示例演示了 goto 的基本功能。

basic_goto.go
package main

import "fmt"

func main() {
    fmt.Println("Start")
    
    goto skip
    fmt.Println("This won't print")
    
skip:
    fmt.Println("End")
}

程序会跳过中间的打印语句,直接跳转到 skip 标签。goto 提供了无条件的控制转移。

循环中的 Goto

goto 可用于跳出嵌套循环。此示例展示了如何使用单个 goto 语句退出多个循环。

loop_goto.go
package main

import "fmt"

func main() {
    for i := 0; i < 3; i++ {
        for j := 0; j < 3; j++ {
            fmt.Printf("i=%d, j=%d\n", i, j)
            
            if i == 1 && j == 1 {
                goto exit
            }
        }
    }
    
exit:
    fmt.Println("Exited both loops")
}

当 i 和 j 都等于 1 时,goto 会跳转到 exit 标签。这会立即退出所有嵌套循环,而无需复杂的条件检查。

使用 goto 进行错误处理

goto 在 Go 中的一个常见用法是错误处理。此模式有助于在发生错误时集中清理代码。

error_goto.go
package main

import (
    "fmt"
    "errors"
)

func main() {
    err := process()
    if err != nil {
        fmt.Println("Error:", err)
    }
}

func process() error {
    resource1 := "open resource1"
    fmt.Println(resource1)
    
    resource2 := "open resource2"
    fmt.Println(resource2)
    
    // Simulate error
    if true {
        return errors.New("something went wrong")
    }
    
    // Cleanup code
    fmt.Println("closing resource2")
    fmt.Println("closing resource1")
    return nil
}

该示例展示了 goto 如何帮助进行资源清理。在实际代码中,您大多数情况下会使用 defer,但对于复杂场景,goto 仍然是一个选项。

带有条件跳转的 Goto

goto 可以实现类似于 if-else 逻辑的条件跳转。此示例演示了备用的控制流。

conditional_goto.go
package main

import "fmt"

func main() {
    num := 7
    
    if num%2 == 0 {
        goto even
    } else {
        goto odd
    }
    
even:
    fmt.Println("Number is even")
    return
    
odd:
    fmt.Println("Number is odd")
}

该程序使用 goto 语句检查数字是偶数还是奇数。虽然对于这种情况来说它不是最佳方法,但它展示了条件跳转。

Goto 的限制

Go 对 goto 施加了限制,以防止出现有问题性的跳转。此示例显示了无效的 goto 用法,这会导致编译错误。

invalid_goto.go
package main

import "fmt"

func main() {
    // This would cause a compile error:
    // goto skip
    // x := 5
    // skip:
    // fmt.Println(x)
    
    // Correct approach:
    x := 5
    goto skip
    fmt.Println("This won't print")
skip:
    fmt.Println(x)
}

您不能跳过变量声明或跳转到其他块。注释掉的代码显示了无效用法,而活动代码演示了正确的 goto 用法。

带 goto 的状态机

goto 可以实现简单的状态机。此示例展示了一个处理输入的三个状态的机器。

state_machine.go
package main

import "fmt"

func main() {
    state := "start"
    
start:
    fmt.Println("State: start")
    state = "process"
    goto process
    
process:
    fmt.Println("State: process")
    state = "end"
    goto end
    
end:
    fmt.Println("State: end")
}

程序使用 goto 语句在三个状态之间移动。每个标签代表机器执行流程中的不同状态。

Goto 与其他控制结构

此示例将 goto 与标准控制结构进行对比,以显示 goto 何时可能适用。

control_comparison.go
package main

import "fmt"

func main() {
    // Standard loop with break
    for i := 0; i < 10; i++ {
        if i == 5 {
            break
        }
        fmt.Println(i)
    }
    
    // Equivalent with goto
    i := 0
loop:
    if i < 10 {
        if i == 5 {
            goto end
        }
        fmt.Println(i)
        i++
        goto loop
    }
end:
}

第一个循环使用标准的 break,而第二个循环使用 goto 实现类似逻辑。在大多数情况下,标准控制结构比 goto 更可取。

来源

Go 语言规范

本教程通过在各种场景中进行受控跳转的实际示例,涵盖了 Go 中的 goto 关键字。

作者

我叫 Jan Bodnar,是一名充满热情的程序员,拥有丰富的编程经验。我从 2007 年开始撰写编程文章。迄今为止,我已撰写了 1400 多篇文章和 8 本电子书。我在编程教学方面拥有十多年的经验。

列出所有 Golang 教程