对于好多其他不支持 Label 方式的语言来说,跳出多重循环是一件比较麻烦的事情。而 Go 支持 Label 方式跳转,且支持 goto 这种逆天跳转,对于多重循环跳转更是小菜一碟。简单来说,goto 语法让 Label 大放异彩。
在 Go 中使用 Label 需要配合
goto,
break,
continue 来使用。
goto
使用 goto 语法的时候,是必须要结合 Label 使用的,语法也比较好理解,就是跳转到对应 Label 的地方继续执行。正因为 Label 配合 goto 使用的情况更多,所以相应的细节也会更多。
goto
必须配合 Label 使用
package main
import (
"fmt"
)
func main() {
fmt.Println(1) // 1
goto End
fmt.Println(2) // 被跳过,不会执行
End:
fmt.Println(3) // 3
}
Label
可以声明在函数体的任何地方
package main
import (
"fmt"
)
func main() {
End:
fmt.Println(1) // loop 1
goto End
fmt.Println(2)
fmt.Println(3)
}
没在函数体中声明而直接使用的话,会导致未定义报错。
package main
import (
"fmt"
)
func main() {
fmt.Println(1)
goto End // label End not defined
fmt.Println(2)
}
End: // syntax error: non-declaration statement outside function body
fmt.Println(3)
Label
在嵌套函数(闭包)也是不可用的 。
package main
import (
"fmt"
)
func main() {
fmt.Println(1)
func() {
fmt.Println("Nested function")
goto End // label End not defined
}()
End: // label End defined and not used
fmt.Println(2)
}
同一个函数作用域不能重复定义 Label
不能重复定义 Label,这个还是比较好理解,毕竟程序要的就是清晰明了。
package main
import (
"fmt"
)
func main() {
fmt.Println(1)
goto End
End: // label End already defined at .\main.go:11:1
fmt.Println(2)
End:
fmt.Println(3)
}
当然,如果本身就没在同个函数体内的话,名称相同也没什么影响(毕竟作用域是不一样的)。
package main
import (
"fmt"
)
func main() {
fmt.Println(1)
goto End
End:
fmt.Println(2)
test()
}
func test() {
fmt.Println("test")
goto End
End:
fmt.Println("end")
}
Label
和变量名不冲突
毕竟 Label 和变量名的用途不一样,是不同的东西,所以相同名称并不会造成语法上的错误。
但是,尽管如此,不建议这么使用。
package main
import (
"fmt"
)
func main() {
x := 1
fmt.Println(x)
goto x
fmt.Println(3)
x:
fmt.Println(2)
}
变量的声明必须在 goto
之前
package main
import (
"fmt"
)
func main() {
goto End // goto End jumps over declaration of j
j := 2
fmt.Println(j)
End:
fmt.Println(1)
}
break
break 单独使用的场景和其他语言并没有什么两样,都是跳出最近一层的循环。
break
携带 Label
可以用在 for,
switch,
select
上,且 Label
必须紧挨着他们。
简单来说,break 配合 Label 使用的时候,break 所在的 for,switch,select 要紧跟在 Label 的后面。
package main
func main() {
FirstLoop:
for i := 0; i < 10; i++ { // invalid break label FirstLoop
}
for i := 0; i < 10; i++ {
break FirstLoop
}
}
package main
import "fmt"
func main() {
FirstLoop:
j := 1
switch j {
case 0:
fmt.Println(0)
case 1:
fmt.Println(1)
break FirstLoop // invalid break label FirstLoop
}
}
跳出多重 for 循环
package main
import "fmt"
func main() {
OuterLoop:
for i := 0; i < 3; i++ {
for j := 0; j < 3; j++ {
fmt.Printf("i=%v, j=%v\n", i, j)
if i == 1 && j == 1 {
break OuterLoop
}
}
}
fmt.Println("end")
}
i=0, j=0
i=0, j=1
i=0, j=2
i=1, j=0
i=1, j=1
end
跳出 switch
package main
import "fmt"
func main() {
SwitchStatement:
switch 1 {
case 1:
fmt.Println(1) // 1
for i := 0; i < 10; i++ {
break SwitchStatement
}
fmt.Println(2) // 2
}
fmt.Println("end")
}
continue
continue 和 break 用法差不多。
package main
import "fmt"
func main() {
OuterLoop:
for i := 0; i < 3; i++ {
for j := 0; j < 3; j++ {
fmt.Printf("i=%v, j=%v\n", i, j)
if i == 1 {
continue OuterLoop
}
}
}
fmt.Println("end")
}
i=0, j=0
i=0, j=1
i=0, j=2
i=1, j=0
i=2, j=0
i=2, j=1
i=2, j=2
end