Go语言不支持传统的 try…catch…finally 这种异常,因为Go语言的设计者们认为,将异常与控制结构混在一起会很容易使得代码变得混乱。因为开发者很容易滥用异常,甚至一个小小的错误都抛出一个异常。在Go语言中,使用多值返回来返回错误。不要用异常代替错误,更不要用来控制流程。在极个别的情况下,也就是说,遇到真正的异常的情况下(比如除数为0了)。才使用Go中引入的Exception处理:defer, panic, recover。流程可以简要描述为:在代码片段中抛出一个panic的异常,然后在defer中通过recover捕获这个异常,然后正常处理
一.使用多返回值来处理错误
import ( "errors" "fmt" ) func Handle(i int) (int, error) { if i == 0 { return i, errors.New("除数为0") } return 100 / i, nil } func main() { if divint, err := Handle(0); err != nil { fmt.Println(err) } else { fmt.Println(divint) } }
二.defer
defer就是用来添加函数结束时执行的语句.因为这个特性,可以将其用作关闭文件句柄等.
func Handle(i int) (res int) { res = i defer func() { res++ }() return res } func main() { i := Handle(0) fmt.Println(i) }
打印出1, 因为defer中添加了一个函数,在函数返回前改变了命名返回值的值.如果defer语句没有执行,那么defer函数不会添加.
func Handle(i int) (res int) { res = i return res // 直接返回了,defer没有执行 defer func() { res++ }() return res } func main() { i := Handle(0) fmt.Println(i) }
二.panic
panic 是用来表示非常严重的不可恢复的错误的.可以理解为一般语言的 throw new Exception().调用panic看看,程序立马挂掉,然后Go运行时会打印出调用栈.
关键的一点是,即使函数执行的时候panic了,函数不往下走了,运行时并不是立刻向上传递panic,而是到defer那,等defer的东西都跑完了,panic再向上传递。所以这时候 defer 有点类似 try-catch-finally 中的 finally。
三.recover
捕获panic,被捕获到的panic就不会向上传递了.不过要注意,recover之后,逻辑并不会恢复到panic那个点去,函数还是会在defer之后返回.
用Go实现类似 try catch 的异常处理:
import ( "fmt" ) func Handle(i int) (res int) { if i == 0 { panic("被除数为0") } res = i / 2 return res } func main() { defer func() { if err := recover(); err != nil { fmt.Println(err) } }() Handle(0) }