寫C/C++的時候, 基本上都是建議不要使用goto的, 因為goto運(yùn)用的不好的話, 會改變程序的運(yùn)行結(jié)構(gòu), 會造成程序運(yùn)行的混亂. 所以很少能看到C++代碼中有使用goto的.
不過看到Golang中, 不僅保留了goto, 而且把它發(fā)揚(yáng)光大了.
在Golang中能使用Label的有goto, break, continue. 這篇文章就介紹下Golang中Label使用和注意點(diǎn).
注意點(diǎn):
-
Label在continue, break中是可選的, 但是在goto中是必須的 - 作用范圍: 定義
Label的函數(shù)體內(nèi). -
Label可以聲明在函數(shù)體的任何位置, 不管Label聲明在調(diào)用點(diǎn)的前面還是后面.
看到國外一篇文章寫的不錯, 加上自己的一些理解, 寫了這么一篇文章.
一. goto
下面就以goto為例子展示上面三點(diǎn)特點(diǎn).
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可以聲明在函數(shù)體的任何地方
package main
import (
"fmt"
)
func main() {
End:
fmt.Println(1)
goto End
fmt.Println(2)
fmt.Println(3)
}
Output
1
1
1
....
3.Label的作用范圍是在函數(shù)體中
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在嵌套函數(shù)(閉包)是不可用的. 不管是在閉包里調(diào)用閉包外的Label, 還是在閉包外調(diào)用閉包里的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.不能重復(fù)定義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是區(qū)分大小寫的.
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.單層循環(huán)
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.雙層循環(huán)
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就能夠?qū)崿F(xiàn)和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
如果想繼續(xù)往下執(zhí)行, 需要使用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在函數(shù)里是不起作用的, 不能傳遞出來.
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就可以直接跳出最外面的循環(huán).
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.正常的用法, 調(diào)過當(dāng)前循環(huán), 繼續(xù)執(zhí)行下一次
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和雙層循環(huán)一起使用
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
參考資料: