Golang Label使用方法

栏目: Go · 发布时间: 5年前

内容简介:写不过看到Golang中, 不仅保留了在Golang中能使用

C/C++ 的时候, 基本上都是建议不要使用 goto 的, 因为 goto 运用的不好的话, 会改变程序的运行结构, 会造成程序运行的混乱. 所以很少能看到C++代码中有使用 goto 的.

不过看到Golang中, 不仅保留了 goto , 而且把它 发扬光大 了.

在Golang中能使用 Label 的有 goto , break , continue . 这篇文章就介绍下Golang中 Label 使用和注意点.

注意点:

  1. Label 在continue, break中是 可选的 , 但是在 goto 中是 必须的
  2. 作用范围: 定义 Label 的函数体内.
  3. Label 可以声明在函数体的任何位置, 不管 Label 声明在 调用点 的前面还是后面.

看到国外一篇 文章 写的不错, 加上自己的一些理解, 写了这么一篇文章.

一. goto

下面就以 goto 为例子展示上面三点特点.

1. Labelgoto 是必须的

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 一般用来跳出 最近 一层的 switchfor , 注意不能用在 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 来使用的.但是在 golangswitch/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
    }
}

对于 selectswitch 也是一样.

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. continuelabel 一起使用(其实和不使用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

参考资料:

  1. Labels in Go
  2. Label Breaks In Go

以上所述就是小编给大家介绍的《Golang Label使用方法》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

编码

编码

查尔斯•佩措尔德 (Charles Petzold) / 左飞、薛佟佟 / 电子工业出版社 / 2012-10-1 / 59.00元

编码:隐匿在计算机软硬件背后的语言,ISBN:9787121181184,作者:(美)佩措尔德(Petzold,C.)著 左飞,薛佟佟译一起来看看 《编码》 这本书的介绍吧!

MD5 加密
MD5 加密

MD5 加密工具

html转js在线工具
html转js在线工具

html转js在线工具