- 在默认情况下,当发生错误(panic)后,程序就会终止运行
- 如果发生错误后,可以捕获错误,并通知管理人员(邮件或者短信),程序还可以继续运行,这当然无可厚非
- errors.New("错误信息"),会返回一个error类型的值,表示一个错误
- panic内置函数,接收一个interface()类型的值(也就是任何值都可以)作为参数,可以接收error类型的变量,输出错误信息,并退出程序
- GO语言追求简洁优雅,GO语言不类似php支出try catch操作
- GO语言中引入的处理方式为:defer、panic、recover
- GO可以抛出一个panic异常。然后在defer中通过recover捕获异常再处理
自定义错误处理运用
package main import ( "fmt"
"errors" ) //此函数读取配置文件信息 //如果文件名不正确,返回自定义错误
func readConfFile(FileName string) (err error) { //返回error类型
if FileName == "config.ini" { return nil //表示没有错误
} else { return errors.New("读取文件错误") } } func error_func(){ err := readConfFile("config.ini") //这里故意写错,报错代码在第一块,如果写对,在第二块
if err != nil { //如果读取文件发生错误,就输出这个错误,并终止程序
panic(err) //这个函数作用是打印错误信息,并终止程序
} fmt.Println("error_func()继续执行") } func main() { error_func() fmt.Printf("发生错误后面的代码") } //【报错信息】 //一、 // panic: 读取文件错误 // goroutine 1 [running]: // main.error_func() // D:/goproject/src/main/hello.go:22 +0xdf // main.main() // D:/goproject/src/main/hello.go:27 +0x27 // exit status 2 //二、 // error_func()继续执行 // 发生错误后面的代码
recover+defer的运用
package main import ( "fmt"
"time" ) //这里举例,在数学计算中0是不可以作为被除数的
func error_func() { //这里使用defer + recover来捕获处理异常
defer func() { //defer就是把匿名函数压入到defer栈中,等到执行完毕后或者发生异常后调用匿名函数
err := recover() //recover是内置函数,可以捕获到异常
if err != nil { //说明有错误
fmt.Println("err=", err) //当然这里可以把错误的详细位置发送给开发人员 //send email to admin
} }() num1 := 10 num2 := 0 res := num1 / num2 fmt.Println("res=", res) } func main() { //这样程序不会轻易挂掉
error_func() i := 0
for { i++ fmt.Println("发生错误后面的代码", i) time.Sleep(time.Second) } }
defer语句是在return之后执行的,例如:
func test() (result int) { defer func() { result = 12 }() return 10 } func main() { fmt.Println(test()) // 12
}
在一个函数中panic被调用后,其defer语句仍会执行,例如:
package main import ( "fmt"
"errors" ) func foo()(n int) { defer func() { if r := recover(); r != nil { fmt.Println("再然后④\n") n++ fmt.Println("最后⑤\n") } }() fmt.Println("首先①\n") n++ fmt.Printf("然后②n=%v\n" ,n) fmt.Println("然后③\n") panic(errors.New("i'm a bug")) fmt.Println("没走\n") return n } func main() {
n := foo() fmt.Printf("n最后的值%v", n) }
首先① 然后②n=1 然后③ 再然后④ 最后⑤ n最后的值2
Recover 是一个Go语言的内建函数,可以让进入宕机流程中的 goroutine 恢复过来,recover 仅在延迟函数 defer 中有效,在正常的执行过程中,调用 recover 会返回 nil 并且没有其他任何效果,如果当前的 goroutine 陷入恐慌,调用 recover 可以捕获到 panic 的输入值,并且恢复正常的执行。
通常来说,不应该对进入 panic 宕机的程序做任何处理,但有时,需要我们可以从宕机中恢复,至少我们可以在程序崩溃前,做一些操作,举个例子,当 web 服务器遇到不可预料的严重问题时,在崩溃前应该将所有的连接关闭,如果不做任何处理,会使得客户端一直处于等待状态,如果 web 服务器还在开发阶段,服务器甚至可以将异常信息反馈到客户端,帮助调试。
提示
在其他语言里,宕机往往以异常的形式存在,底层抛出异常,上层逻辑通过 try/catch 机制捕获异常,没有被捕获的严重异常会导致宕机,捕获的异常可以被忽略,让代码继续运行。
Go语言没有异常系统,其使用 panic 触发宕机类似于其他语言的抛出异常,recover 的宕机恢复机制就对应其他语言中的 try/catch 机制
panic 和 recover 的关系
panic 和 recover 的组合有如下特性:
- 有 panic 没 recover,程序宕机。
- 有 panic 也有 recover,程序不会宕机,执行完对应的 defer 后,从宕机点退出当前函数后继续执行。
提示
虽然 panic/recover 能模拟其他语言的异常机制,但并不建议在编写普通函数时也经常性使用这种特性。
在 panic 触发的 defer 函数内,可以继续调用 panic,进一步将错误外抛,直到程序整体崩溃。
如果想在捕获错误时设置当前函数的返回值,可以对返回值使用命名返回值方式直接进行设置。