/ 读书笔记

Go语言圣经 学习笔记 第五章(第二部分)

第五章 函数

  • 本章主要讨论了GO语言的函数特性

5.7 可变参数

  • 在声明可变参数函数时,需要在参数列表的最后一个参数类型之前加上省略符号“...”,这表示该函数会接收任意数量的该类型参数
func sum(vals...int) int {
    total := 0
    for _, val := range vals {
        total += val
    } 
    return total
}
  • 如果原始参数已经是切片类型,我们该如何传递给sum?只需
    在最后一个参数后加上省略符,如
values := []int{1, 2, 3, 4}
fmt.Println(sum(values...)) // "10"

5.8 Deferred函数

  • 当defer语句被执行时,跟在defer后面的函数会被延迟执行。直到包含该defer语句的函数执行完毕时,defer后的函数才会被执行,不论包含defer语句的函数是通过return正常结束,还是由于panic导致的异常结束。你可以在一个函数中执行多条defer语句,它们的执行顺序与声明顺序相反。
  • defer语句经常被用于处理成对的操作,如打开、关闭、连接、断开连接、加锁、释放锁。通过defer机制,不论函数逻辑多复杂,都能保证在任何执行路径下,资源被释放
  • defer机制也常被用于记录何时进入和退出函数。下例中的
    bigSlowOperation函数
func bigSlowOperation() {
    defer trace("bigSlowOperation")() // don't forget the extra parentheses
    // ...lots of work…
    time.Sleep(10 * time.Second) // simulate slow
    operation by sleeping
} 
func trace(msg string) func() {
    start := time.Now()
    log.Printf("enter %s", msg)
    return func() {
        log.Printf("exit%s(%s)",msg,time.Since(start))
    }
}

需要注意一点:不要忘记defer语句后的圆括号,否则本该在进入时执行的操作会在退出时执行,而本该在退出时执行的,永远不会被执行.当执行到defer定义时,首先会对参数进行求值,然后参数被压入函数调用栈,此时不会进入defer函数体,而是直到函数返回时才调用defer函数体。参数被压入函数调用栈时,如果参数是值类型,那么将复制值,如果参数是指针,那么将复制指针而不是复制指针指向的值。
ps:上面的例子中,加了小括号之后,运行了函数体trace的

    start := time.Now()
    log.Printf("enter %s", msg)
    ...

部分是因为它要求得defer后面要执行的函数

5.9 Panic异常

  • 虽然Go的panic机制类似于其他语言的异常,但panic的适用场景有一些不同。由于panic会引起程序的崩溃,因此panic一般用于严重错误,如程序内部的逻辑不一致。勤奋的程序员认为
    任何崩溃都表明代码中存在漏洞,所以对于大部分漏洞,我们应该使用Go提供的错误机制,而不是panic,尽量避免程序的崩溃。
  • 获取堆栈信息
func printStack() {
    var buf [4096]byte
    n := runtime.Stack(buf[:], false)
    os.Stdout.Write(buf[:n])
}

5.9 Recover捕获异常

  • 如果在deferred函数中调用了内置函数recover,并且定义该defer语句的函数发生了panic异常,recover会使程序从panic中恢复,并返回panic value。导致panic异常的函数不会继续运
    行,但能正常返回。在未发生panic时调用recover,recover会返回nil。
func Parse(input string) (s *Syntax, err error) {
    defer func() {
        if p := recover(); p != nil {
            err = fmt.Errorf("internal error: %v", p)
        }
    }()
    // ...parser...
}