Go语言设计者认为类似try-catch-finally的传统异常处理机制很容易造成开发者对异常机制的滥用,Go语言中推荐多值返回来返回错误,这种检查错误的方式给程序员提供了很大的控制权。
错误定义:
error类型其实是一个接口。
type error interface{
Error() string
}
error接口包含Error()方法,返回一个字符串。这意味着所有包含Error() string 格式的方法都可以实现错误接口
创建错误:使用errors包的New函数创建自定义错误
func main(){
err := errors.New("this is a err!")
var err2 error
fmt.Println(err.Error())
fmt.Println(err) //同上
fmt.Println(err2)
}
//结果为:
this is a err!
this is a err!
<nil>
自定义错误格式:fmt.Errorf() 本质上还是调用errors包的New方法创建错误,并使用Springf方法对错误格式化。
func main(){
if _,_,line,ok := runtime.Caller(0);ok{
err := fmt.Errorf("***Line %d error***",line)
fmt.Println(err.Error())
}
}
//fmt.Errorf()源码
func Errorf(format string,a ...interface{}) error {
return errors.New(Sprintf(format,a...))
}
触发宕机
一般而言,只有当程序发生不可逆的错误时,才使用panic方法触发宕机。
func panic (v interface{}) 可以看到传入任意类型的值作为宕机内容都可以
使用panic方法后,程序的执行将直接中断,但是会调用延迟执行语句defer,可与recover()配合捕获宕机
func main(){
panic("serious bug")
fmt.Println("Invalid Code") //程序退出,无法执行该行代码
}
适用场景:
1、程序处于失控状态且无法恢复,继续执行将影响其他正常程序,引发操作系统异常甚至是死机
2、发生不可预知的错误
宕机恢复
通过内置函数recover来捕获宕机,类似try-catch机制
在使用panic方法触发宕机后,在推出当前函数之前,会调用延迟执行语句defer。
故我们可以通过defer语句+匿名函数+recover方法完成对宕机的捕获
func protect(){
defer func(){
if err := recover();err !=nil{ //recover()获取panic()传入的参数
fmt.Println(err)
}
}()
panic("serious bug!")
}
func main(){
protect()
fmt.Println("valid code")
}
//结果为:
serious bug!
valid code
recover应用:安全模式
专门封装一个函数,以一种安全模式来运行所有传入的方法
func protect(f func()){
defer func(){
if err := recover();err!= nil{
fmt.Println(err)
}
}()
f()
}
func main(){
protect(func () {
fmt.Println("This is function 1")
panic("Serious bug from function1")
})
protect(func () {
fmt.Println("This is function 2")
panic("Serious bug from function2")
})
fmt.Println("valid code")
}
//结果为:
This is function 1
Serious bug from function1
This is function 2
Serious bug from function2
valid code
panic()和recover()虽然可以模拟其他语言的异常机制,但是并不建议在Go语言编程中使用类似的方法,推荐使用多值返回错误。
拓展:error 接口的应用
上面说到实现Error()string的接口都可以实现error接口
type ErrNegSqrt float64
func (e ErrNegSqrt) Error() string{
return fmt.Printf("cannot Sqrt negative number: %v",float64(e))
}
func sqrt(x float64) (float64,error){
if x < 0.0{
return 0,ErrNegSqrt(x)
}else{
return math.Sqrt(x),nil
}
}
func main(){
res,err := sqrt(-2)
if err != nil{
fmt.Println(err)
}else{
fmt.Println(res)
}
}
//结果为:
cannot Sqrt negative number: -2