Go中的标签

Go中的标签Label 在 break

Label 在 break 和 continue 语句中是可选参数,而在 goto 语句中是必传的参数。Label 只在声明它的函数中有效。只要函数中声明了 Label ,那它在该函数的整个作用域都有效。

func main() {
    fmt.Println(1)
    goto End
    fmt.Println(2)
End:
    fmt.Println(3)
}

(注意!我们是在 goto 语句之后定义的 Label)

> ./bin/sandbox
1
3

这里所指的作用域不包括嵌套函数的作用域:

func() {
        fmt.Println(“Nested function”)
        goto End
    }()
End:

上面这段代码在编译时会报 label End not defined 错误。除此之外还会报:label End defined and not used,因为我们需要保证只声明需要使用的 Label。
Label 中没有块作用域的概念。所以不能在嵌套的块作用域中声明重复的 Label:

goto X
X:
    {
        X:
    }

编译上面的代码会报错提示 Label 已经存在了。
Label 的标识符和其他标识符具有不同的命名空间,所以不会与变量标识符等发生冲突。下面这段代码同时在 Label 和变量声明中都使用 x 作为标识符:

    x := 1
    goto x
x:
    fmt.Println(x)

break 语句
break 语句一般都是用来跳出 for 或 switch 语句。在 Go 中也可以在 select 语句中使用 break。
对于拥有类 C 语言编程经验的人肯定知道每个 case 语句都需要以 break 结尾。但是在大多数情况下程序都不希望执行到下一个 case 语句中。在 Go 中恰恰相反,如果需要执行下一个分句的代码可以使用 fallthrough 语句:

switch 1 {
case 1:
    fmt.Println(1)
case 2:
    fmt.Println(2)
}
> ./bin/sandbox
1
switch 1 {
case 1:
    fmt.Println(1)
    fallthrough
case 2:
    fmt.Println(2)
}
> ./bin/sandbox
1
2

fallthrough 只能作为一个分句的最后一条语句使用。
break 语句不能跨越函数边界。

func f() {
    break
}
func main() {
    for i := 0; i < 10; i++ {
        f()
    }
}

上面的代码会报 break is not in a loop 错误。
一般情况下,break 可以用来跳出 for ,switch 或 select 语句。使用 Label 让 break 可以做更多的事情。
break 语句的 Label 必须对应围绕 break 的 for,switch 或 select 语句。所以下面的代码不能通过编译:

FirstLoop:
    for i := 0; i < 10; i++ {
    }
    for i := 0; i < 10; i++ {
        break FirstLoop
    }

它会报 invalid break label FirstLoop 。因为 Label 不在 break 对应的循环上。
break 可以跳出嵌套的循环:

OuterLoop:
    for i := 0; i < 10; i++ {
        for j := 0; j < 10; j++ {
            fmt.Printf(“i=%v, j=%v\n”, i, j)
            break OuterLoop
        }
    }
> ./bin/sandbox
i=0, j=0

如果 break 像下面这样用,那它不仅仅是退出 for 循环:

SwitchStatement:
    switch 1 {
    case 1:
        fmt.Println(1)
        for i := 0; i < 10; i++ {
            break SwitchStatement
        }
        fmt.Println(2)
    }
    fmt.Println(3)
> ./bin/sandbox
1
3

break 可以在 for,switch 或 select 语句中的任何地方退出并切换到指定 Label。
continue 语句
他和 break 语句相似,只是会进入下一次迭代而不是退出循环(只能在循环中使用):

OuterLoop:
    for i := 0; i < 3; i++ {
        for j := 0; j < 3; j++ {
            fmt.Printf(“i=%v, j=%v\n”, i, j)
            continue OuterLoop
        }
    }
> ./bin/sandbox
i=0, j=0
i=1, j=0
i=2, j=0

goto 语句

goto 语句可以让程序切换到某个被 Label 标记的地方继续执行。

    i := 0
Start:
    fmt.Println(i)
    if i > 2 {
        goto End
    } else {
        i += 1
        goto Start
    }
End:

(注意:End 可以为空)
与 break 和 continue 语句不同,goto 语句必须指定 Label。
goto 只能让程序移动到相同函数的某个位置。因此在执行 goto 的时候还有另外两条规则:
不能跳过变量声明,如果 goto 跳过,编译器会报 

goto Done jumps over declaration of v at…
goto Done
    v := 0
Done:
    fmt.Println(v)

goto

不能切换到其他代码块,如果切换,编译器会报 
goto Block jumps into block starting at …

goto Block
{
Block:
    v := 0
    fmt.Println(v)
}


添加新评论