写C/C++
的时候, 基本上都是建议不要使用goto
的, 因为goto
运用的不好的话, 会改变程序的运行结构, 会造成程序运行的混乱. 所以很少能看到C++代码中有使用goto
的.
不过看到Golang中, 不仅保留了goto
, 而且把它发扬光大
了.
在Golang中能使用Label
的有goto
, break
, continue
. 这篇文章就介绍下Golang中Label
使用和注意点.
注意点:
-
Label
在continue, break中是可选的
, 但是在goto
中是必须的
- 作用范围: 定义
Label
的函数体内. -
Label
可以声明在函数体的任何位置, 不管Label
声明在调用点
的前面还是后面.
看到国外一篇文章写的不错, 加上自己的一些理解, 写了这么一篇文章.
一. goto
下面就以goto
为例子展示上面三点特点.
1.Label
在goto
是必须的
package main
import (
"fmt"
)
func main() {
fmt.Println(1)
goto End
//goto 10: syntax error: unexpected . at end of statement
fmt.Println(2)
End:
fmt.Println(3)
}
Output:
1
3
2.Label
可以声明在函数体的任何地方
package main
import (
"fmt"
)
func main() {
End:
fmt.Println(1)
goto End
fmt.Println(2)
fmt.Println(3)
}
Output
1
1
1
....
3.Label
的作用范围是在函数体中
package main
import (
"fmt"
)
func main() {
fmt.Println(1)
goto End
fmt.Println(2)
}
End:
fmt.Println(3)
Output:
syntax error: non-declaration statement outside function body
4.Label
在嵌套函数(闭包)是不可用的. 不管是在闭包里
调用闭包外
的Label, 还是在闭包外
调用闭包里
的Label
package main
import (
"fmt"
)
func main() {
fmt.Println(1)
func() {
fmt.Println("Nested function")
goto End
}()
End:
fmt.Println(2)
}
Output
11:label End not defined
13:label End defined and not used
5.不能重复定义Label
package main
import (
"fmt"
)
func main() {
fmt.Println(1)
goto End
End
fmt.Println(2)
{
End:
fmt.Println(3)
}
}
Output
14: label End already defined at ./label.go:11
6.Label
和变量名是不冲突的
, 可以定义一个名为x
的变量和名为x
的Label(不过不建议这么用, 这么写会被人骂的); 而且Label
是区分大小写的.
package main
import (
"fmt"
)
func main() {
x := 1
fmt.Println(x)
goto x
x:
fmt.Println(2)
}
Output:
1
2
7.变量的声明必须在goto
之前.
package main
import (
"fmt"
)
func main() {
goto End
j := 2
fmt.Println(j)
End:
fmt.Println(1)
}
Output
goto End jumps over declaration of i at ./label.go:9
这是为什么呢? 因为任何变量的声明都不能被跳过.
需要改成下面的形式
package main
import (
"fmt"
)
func main() {
j := 2
goto End
fmt.Println(j)
End:
fmt.Println(2)
}
二. break(不带label)
break
一般用来跳出最近
一层的switch
和for
, 注意不能用在select
上
1.单层循环
package main
import (
"fmt"
)
func main() {
for i := 0; i < 10; i++ {
fmt.Println(i)
if i == 3 {
break
}
}
}
Output
0
1
2
3
2.双层循环
package main
import (
"fmt"
)
func main() {
for i := 0; i < 3; i++ {
for j := 0; j < 5; j++ {
fmt.Println("i:", i, ",j:", j)
if j == 2 {
break
}
}
}
}
Output
i: 0 ,j: 0
i: 0 ,j: 1
i: 0 ,j: 2
i: 1 ,j: 0
i: 1 ,j: 1
i: 1 ,j: 2
i: 2 ,j: 0
i: 2 ,j: 1
i: 2 ,j: 2
从这个例子可以看出break
只能跳出最近for
3.对于c/c++
来说, switch/case
一般都是配合break
来使用的.但是在golang
中switch/case
不需要break
就能够实现和c/c++
一样的效果.
package main
import (
"fmt"
)
func main() {
i := 1
switch {
case i == 0:
fmt.Println(i)
case i == 1:
fmt.Println(i)
//break 这里可以使用`break`,但是么有啥效果, 不如不写
case i == 2:
fmt.Println(i)
}
}
Output
1
如果想继续往下执行, 需要使用fallthrough
package main
import (
"fmt"
)
func main() {
i := 1
switch {
case i == 0:
fmt.Println(0)
case i == 1:
fmt.Println(1)
fallthrough
case i == 2:
fmt.Println(2)
}
}
Output:
1
2
4.break
在函数里是不起作用的, 不能传递出来.
package main
func f() {
break
}
func main() {
for i := 0; i < 10; i++ {
f()
}
}
output
4: break is not in a loop
三.break(Label)
break
携带label
可以用在for
,switch
,select
上.
1.对于for
/select
/switch
,Label
必须紧挨着他们.
FirstLoop:
for i := 0; i < 10; i++ { //invalid break label FirstLoop
}
for i := 0; i < 10; i++ {
break FirstLoop
}
必须改成这样
func main() {
for i := 0; i < 10; i++ {
fmt.Println(i)
}
FirstLoop:
for i := 0; i < 10; i++ {
break FirstLoop
}
}
对于select
和switch
也是一样.
func main() {
FirstLoop:
j := 1
switch j {
case 0:
fmt.Println(0)
case 1:
fmt.Println(1)
break FirstLoop // invalid break label FirstLoop
}
}
2.一般来说break
只能跳出最近一层的for
, switch
, 但是break Label
就可以直接跳出最外面的循环.
func main() {
OuterLoop:
for i := 0; i < 10; i++ {
for j := 0; j < 10; j++ {
fmt.Printf("i=%v, j=%v\n", i, j)
break OuterLoop
}
}
}
Output
i=0, j=0
SwitchStatement:
switch 1 {
case 1:
fmt.Println(1)
for i := 0; i < 10; i++ {
break SwitchStatement
}
fmt.Println(2)
}
fmt.Println(3)
Output
1
3
四. continue
continue
用法基本上和break
差不多.
1.正常的用法, 调过当前循环, 继续执行下一次
package main
import (
"fmt"
)
func main() {
for i := 0; i < 5; i++ {
if i == 3 {
continue
}
fmt.Println(i)
}
}
Output
0
1
2
4
2.continue
和label
一起使用(其实和不使用Label效果一样)
func main() {
Test:
for i := 0; i < 5; i++ {
if i == 3 {
continue Test
}
fmt.Println(i)
}
}
Output
0
1
2
4
3.continue
和双层循环一起使用
OuterLoop:
for i := 0; i < 3; i++ {
for j := 0; j < 3; j++ {
fmt.Printf(“i=%v, j=%v\n”, i, j)
continue OuterLoop
}
}
Output
i=0, j=0
i=1, j=0
i=2, j=0
参考资料:
有疑问加站长微信联系(非本文作者)