39

【Go】了解Defer、Panic、Recover

 4 years ago
source link: https://www.tuicool.com/articles/iyumu2Z
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Go 有流程控制的机制: ifforswitchgoto 。这里我们讨论并不常见的: deferpanicrecover

一个 defer语句 会把一个函数压入一个栈中,当外层函数返回时,会按照后进先出的顺序执行压入的函数。 defer 有三个简单的规则:

  1. 当defer语句执行的时候,函数的参数也被指定。 在这个例子中,当Println被延迟执行的时候变量 i 的值已经被赋值,所以会打印 0 而不是 1
func a() {
    i := 0
    defer fmt.Println(i)
    i++
    return
}
复制代码
  1. 被defer的函数在外层函数返回后遵循后进先出的规则依次被调用。 这个例子将返回 3210
func b() {
    for i := 0; i < 4; i++ {
        defer fmt.Print(i)
    }
}
复制代码

3.被defer的函数可以对外层函数的返回值读取并且赋值,计算。 这个例子将返回2:

func c() (i int) {
    defer func() {
        i++
    }()
    return 1
}
复制代码

Panic是一个内置函数,可以停止正常的流程,然后开始_panicking_。当函数 F 调用panic, F 停止,然后 F 内的被 deffer 的函数将被执行,然后 F 返回给调用者。对于调用者来说, F 调用了 panic 。然后继续往上层函数返回,直到当前的 goroutine 返回。 Recover 是一个内置函数,可以捕获到 panic ,Recover只在defer函数中有用。正常的逻辑,recover返回nil,如果当前的goroutine异常,recover将获取panic的值,然后执行逻辑,不会使进程down掉。 这个例子演示了panic和defer的机制:

package main
import "fmt"
func main() {
    f()
    fmt.Println("Returned normally from f.")
}
func f() {
    defer fun() {
        if err := recover(); err != nil {
            fmt.Prinfln("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"m i))
    }
    defer fmt.Println("Defer in g", i)
    fmt.Println("Printing in g", i)
    g(i + 1)
}
复制代码

这个程序将输出:

Calling g.
Printing in g 0
Printing in g 1
Printing in g 2
Printing in g 3
Panicking!
Defer in g 3
Defer in g 2
Defer in g 1
Defer in g 0
Recovered in f 4
Returned normally from f.
复制代码

参考资料:


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK