go的defer-panic-and-recover
Go 是怎么处理普通错误的呢?
通过在函数和方法中返回错误对象作为它们的唯一或最后一个返回值 —— 如果返回 nil,则没有错误发生 —— 并且主调(calling)函数总是应该检查收到的错误。
1、产生错误的函数会返回两个变量,一个值和一个错误码;如果后者是 nil 就是成功,非 nil 就是发生了错误。
2、为了防止发生错误时正在执行的函数(如果有必要的话甚至会是整个程序)被中止,在调用函数后必须检查错误。
fmt
log
都可以打印错误信息,使程序不会终止。
如果要终止程序,可以用panic(err),在终止的同时,打印错误信息。
os.Exit(1)
return
预先定义的error接口类型
errors.New()创建一个errorString结构体
errorString结构体实现了error接口
错误字符串不能包含大写或以标点符号结束。
比如Math是不推荐的,number。也是不推荐的。
类型断言和类型判断
所有的例子都遵循同一种命名规范:错误类型以 “Error” 结尾,错误变量以 “err” 或 “Err” 开头。
if len(os.Args) > 1 && (os.Args[1] == "-h" || os.Args[1] == "--help") {
err = fmt.Errorf("usage: %s infile.txt outfile.txt", filepath.Base(os.Args[0]))
}
不能随意地用 panic 中止程序,必须尽力补救错误让程序能继续执行。
从panic中恢复(recover) 类似try except
注意:recover只能在 defer修饰的函数中使用 用于取得panic调用中传递过来的错误值
即便发生了panic,defer还是会执行,因此recover需要写在defer修饰的函数中
如果没有发生panic,调用recover会返回nil,没有影响
defer func(){
recover()
}()
总结:panic 会导致(栈被展开)直到 defer 修饰的 recover () 被调用或者程序中止。
如果创建了自定义包:
1)在包内部,总是应该从 panic 中 recover:不允许显式的超出包范围的 panic ()
2)向包的调用者返回错误值(而不是 panic)。
每当函数返回时,我们应该检查是否有错误发生:但是这会导致重复乏味的代码。
err1 := func1()
if err1 != nil {}
err2 := func2()
if err2 != nil {}
err3 := func3()
if err3 != nil {}
使用闭包处理错误
如果一段代码重复了多次,就有必要将它提取出来了。
首先执行f()
1、将f()中的defer语句放入栈中最底层
2、打印"开始调用g"
此时的数据为:
然后执行g(0)
此时的数据为:
然后执行g(1)
此时的数据为:
然后执行g(2)
此时的数据为:
然后执行g(3)
此时的数据为:
然后执行g(4)
注意这一步:因为 4 > 3,此时执行:
首先打印Panicking!
然后执行Panic(4)
注意:程序遇到panic时,会遍历defer栈(按照后进先出的原则),并执行每个defer。
此时的数据如下:
当遍历到最底层的那个defer时,由于该defer里面有recover,因此程序会停止panic。
此时的数据为:
此时程序就执行完毕了。
上面是在最后一个defer处遇到了recover(),如果没有遇到,那么在遍历完defer链表后,将向stderr抛出panic信息。