错误和异常的区别
-
错误指的是可能出现问题的地方出现了问题,比如打开一个文件时失败,这种情况在人们的意料之中 ;而异常指的是不应该出现问题的地方出现了问题,比如引用了空指针,这种情况在人们的意料之外。可见,错误是业务过程的一部分,而异常不是 。
-
错误和异常从Golang机制上讲,就是error和panic的区别。
-
Golang错误和异常是的互相转换的:
错误转异常,比如程序逻辑上尝试请求某个URL,最多尝试三次,尝试三次的过程中请求失败是错误,尝试完第三次还不成功的话,失败就被提升为异常了。
异常转错误,比如panic触发的异常被recover恢复后,将返回值中error类型的变量进行赋值,以便上层函数继续走错误处理流程。
-
Go语言中,一旦某一个协程发生了panic而没有被recover,那么会导致整个go程序都会终止
关于异常与错误设计原则
错误设计:
- 如果失败原因只有一个,则返回bool
- 如果失败原因超过一个,则返回error
- 如果没有失败原因,则不返回bool或error
- 如果重试几次可以避免失败,则不要立即返回bool或error
异常设计:
- 在程序开发阶段,坚持速错,让程序异常崩溃
- 在程序部署后,应恢复异常避免程序终止
- 对于不应该出现的分支,使用异常处理
Go内置error接口处理用来处理错误
// The error built-in interface type is the conventional interface for
// representing an error condition, with the nil value representing no error.
type error interface {
Error() string
}
内置new实现接口的实现
// New returns an error that formats as the given text.
// Each call to New returns a distinct error value even if the text is identical.
func New(text string) error {
return &errorString{text}
}
// errorString is a trivial implementation of error.
type errorString struct {
s string
}
func (e *errorString) Error() string {
return e.s
}
Go内置异常处理函数
- Go内置函数panic和recover来触发和终止异常处理流程,同时引入关键字defer来延迟执行defer后面的函数。
- defer延迟函数总是在异常panic或者正常return前返回
func main(){ defer fmt.Println(123) defer fmt.Println(456) panic("panic") } /* output: 456 123 panic: panic */
- panic是函数时,总是先执行;之后才会执行defer函数,最后返回panic
可以在defer中通过recover关键字恢复我们的panic,将之处理后转化为一个错误并打印(异常转错误)func main(){ defer fmt.Println(123) defer fmt.Println(456) panic(test()) } func test()string{ fmt.Println("akjfjk") return "test" } /* output: akjfjk 456 123 panic: test */
func TestDeferAndRecover(){ defer func(){ if err:=recover(); err != nil{ fmt.Println("err is:",err) } }() panic("panic has happended") } /* output: err is: panic has happended */
Go异常错误处理案例
开始代码
func divi(x,y int) (int,error){
if y == 0{
return 0,errors.New("y can`t be zero")
}
z := x / y
return z ,nil
}
/*
divi(1,0)
output:
0 y can`t be zero
*/
当没有考虑到y不可以为零时;可以使用recover来捕捉panic,defer来延迟执行;作为错误来返回(避免异常导致整个程序Down掉)
func divi(x,y int) (z int,err error){
defer func() {
if e := recover();e!=nil{
err =e.(error)
}
}()
z = x / y
return z ,nil
}
/*
output:
0 runtime error: integer divide by zero
*/
自定义错误类型
首先需要实现error这个接口类
type DIYerror struct{
e string
param string
}
func (d *DIYerror)Error()string{
obj:= bytes.Buffer{}
obj.WriteString("err is:")
obj.WriteString(d.e)
obj.WriteString("param is:")
obj.WriteString(d.param)
return obj.String()
}
func divi(x,y int) (z int,err error){
if y == 0 {
return 0,&DIYerror{
e: "y can`t be 0",
param: strings.Join([]string{strconv.Itoa(x),strconv.Itoa(y)},","),
}
}
z = x / y
return z ,nil
}
/*
output;
0 err is:y can`t be 0param is:1,0
*/