Skip to content

FlowControl #9

@oufeng

Description

@oufeng
  • for

    没有(), 始终需要{}

    for i := 0; i < 10; i++ {
    	sum += i
    }
    

    只天中间项,这样就相当于while

    for sum < 1000 {
    	sum += sum
    }
    

    中间项都不填就是死循环了

    for {
    }
    
  • if

    没有(), 始终需要{}

    if x < 0 {
    	return sqrt(-x) + "i"
    }
    

    可以在if后声明变量,变量的作用域为整个if语句

    if v := math.Pow(x, n); v < lim {
    	return v
    } else {
    	fmt.Printf("%g >= %g\n", v, lim)
    }
    
  • Switch

    可以在Switch后声明变量,变量的作用域为整个Switch语句
    每个case语句默认会加上break;

    func main() {
        fmt.Println("When's Saturday?")
        today := time.Now().Weekday()
        switch time.Saturday {
        case today + 0:
            fmt.Println("Today.")
        case today + 1:
            fmt.Println("Tomorrow.")
        case today + 2:
            fmt.Println("In two days.")
        default:
            fmt.Println("Too far away.")
        }
    }
    

    没有变量会默认为true,相当于if-else

    func main() {
        t := time.Now()
        switch {
        case t.Hour() < 12:
            fmt.Println("Good morning!")
        case t.Hour() < 17:
            fmt.Println("Good afternoon.")
        default:
            fmt.Println("Good evening.")
        }
    }
    
  • Defer

    defer是Go语言提供钩子。该钩子在当前函数执行完毕后(包括通过return正常结束或者panic导致的异常结束)执行

    defer语句通常用于一些成对操作的场景:打开连接/关闭连接;加锁/释放锁;打开文件/关闭文件等

    执行过程

    • 每次defer语句执行的时候,会把函数"压栈",函数参数会被拷贝下来
    • 当外层函数(非代码块,如一个for循环)退出时,defer函数按照定义的逆序执行
    • 如果defer执行的函数为nil, 那么会在最终调用函数的产生panic

    一切从go函数返回值可以被命名说起

    如下,split的返回值被命名为xy

    func split(sum int) (x, y int) {
        x = sum * 4 / 9
        y = sum - x
        return
    }
    

    简单hello world函数

    func helloWorld() {
        return "Hello world"
    }
    

    可被理解成

    func helloWorld(rval string) {
        rval = "Hello world"
        return
    }
    

    defer关键字在编译过后就相当于在return关键字前执行defer_func

    rval = xxx
    defer_func
    return
    

    演示

    函数压栈操作

    func main() {
        for i := 0; i < 5; i++ {
            defer fmt.Println(i)
        }
    }
    
    $ go run main.go
    4
    3
    2
    1
    0
    

    int类型为值拷贝,所以返回值为5

    func f() int {
        i := 5
        defer func() {
            i++
        }()
        return i
    }
    
    func f() (rval int) {
        i := 5
        rval = i
        func() {
            i++
        }()
        return
    }
    

    返回变量为resultresultdefer被修改。所以返回值为1

    func f1() (result int) { 
        defer func() { 
            result++ 
        }() 
        return 0
    }
    
    func f1() (result int) {
        result = 0
        func() { 
            result++ 
        }()
        return
    }
    

    int类型为值拷贝,所以返回值为5

    func f2() (r int) { 
        t := 5 
        defer func() { 
            t = t + 5 
        }()
        return t
    }
    
    func f2() (r int) {
        t := 5 
        r = t
        func() { 
            t = t + 5 
        }()
        return
    }
    

    函数的值都会被拷贝,不影响原来的参数。返回值为1

    func f3() (r int) { 
        defer func(r int) { 
            r = r + 5 
        }(r) 
        return 1
    }
    
    func f3() (r int) {
        r = 1
        func(r int) { 
            r = r + 5 
        }(r) 
        return
    }
    
  • panic和recover。可以简化错误处理

    panic会先处理完当前goroutine已经defer挂上去的任务,执行完毕后再退出整个程序

    可以通过recover在当前goroutine捕捉panicrecover只在defer的函数中有效

    package main
    
    import "fmt"
    
    func main() {
        f()
        fmt.Println("Returned normally from f.")
    }
    
    func f() {
        defer func() {
            if r := recover(); r != nil {
                fmt.Println("Recovered in f", r)
            }
        }()
        fmt.Println("Calling g.")
        g(0)
        fmt.Println("Returned normally from g.")
    }
    
    func g(i int) {
        if i > 3 {
            fmt.Println("Panicking!")
            panic(fmt.Sprintf("%v", i))
        }
        defer fmt.Println("Defer in g", i)
        fmt.Println("Printing in g", i)
        g(i + 1)
    }
    
  • 参考
    Defer, Panic, and Recover
    深入理解 Go 语言 defer

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions