Golang Label使用方法

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

内容简介:写不过看到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使用方法》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

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

Clean Code

Clean Code

Robert C. Martin / Prentice Hall / 2008-8-11 / USD 49.99

Even bad code can function. But if code isn’t clean, it can bring a development organization to its knees. Every year, countless hours and significant resources are lost because of poorly written code......一起来看看 《Clean Code》 这本书的介绍吧!

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

在线进制转换器
在线进制转换器

各进制数互转换器

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换