zoukankan      html  css  js  c++  java
  • Golang中Label的用法

    在Golang中能使用Label的有gotobreakcontinue.,这篇文章就介绍下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只能跳出最近一层的forswitch, 但是break Label就可以直接跳出最外面的循环.

    func main() {
    OuterLoop:
        for i := 0; i < 10; i++ {
            for j := 0; j < 10; j++ {
                fmt.Printf("i=%v, j=%v
    ", 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
    ”, i, j)
                continue OuterLoop
            }
        }

     输出

    Output
    i=0, j=0
    i=1, j=0
    i=2, j=0
    
  • 相关阅读:
    从Linux内核中获取真随机数【转】
    linux下pthread_cancel无法取消线程的原因【转】
    LINUX-内核-中断分析-中断向量表(3)-arm【转】
    ARM中断向量表与响应流程【转】
    小任务与工作队列的区别【转】
    GNU Readline 库及编程简介【转】
    Linux 内核同步之自旋锁与信号量的异同【转】
    Professional Linux Kernel Architecture 笔记 —— 中断处理(Part 2)【转】
    Linux中断(interrupt)子系统之二:arch相关的硬件封装层【转】
    浅谈C语言中的强符号、弱符号、强引用和弱引用【转】
  • 原文地址:https://www.cnblogs.com/zhangyafei/p/13938116.html
Copyright © 2011-2022 走看看