go语言通过error接口实现错误处理的标准模式,在go中山没有异常的,可以通过返回值信息告诉调用者是否发生了错误。一般而言,我们需要定义返回错误的值,如果没有定义错误处理,那就会抛出错误信。
1.错误处理errors.New()
- error接口通常error接口,通过errors包中的
errors.New()
和fmt.Errorf
方法进行创建。 - error
error如果没有错误就会返回nil,如果有就返回创建的错误信息
我们先看没有错误处理的情景,比如下面这段代码:
package main
import "fmt"
func division(a,b int) int {
return a / b
}
func main(){
fmt.Println(division(9,3))
fmt.Println(division(1,0))
}
运行
[root@linuxea.com /opt/Golang/work3]# go run error1.go
3
panic: runtime error: integer divide by zero
goroutine 1 [running]:
main.division(...)
/opt/Golang/work3/error1.go:4
main.main()
/opt/Golang/work3/error1.go:8 +0x88
exit status 2
errors.New()
我们通过errors包中的errors.New()
函数来创建
我们定义返回值的错误类型,如下:
首先判断,行参b等于0就返回-1,并且返回errors.New("division by zero")
。反之返回a除以b,和nil
func division(a,b int) (int,error) {
if b == 0 {
return -1,errors.New("division by zero")
}
return a / b,nil
}
在main函数中,也需要做处理,division函数中返回了两个返回值,main中接收,在做处理,如果返回的是nil,说明没有错误,直接打印返回的int,否则就将接收的errors返回值打印出来
func main(){
fmt.Println(division(9,3))
if v,err := division(1,0);err != nil{
fmt.Println(err)
}else {
fmt.Println(v)
}
}
代码块
package main
import (
"fmt"
"errors"
)
func division(a,b int) (int,error) {
if b == 0 {
return -1,errors.New("division by zero")
}
return a / b,nil
}
func main(){
fmt.Println(division(9,3))
if v,err := division(1,0);err != nil{
fmt.Println(err)
}else {
fmt.Println(v)
}
}
运行
[root@linuxea.com /opt/Golang/work3]# go run error.go
3 <nil>
division by zero
fmt.Errorf()
除了errors.New
还有在fmt
包中的Errorf
函数。我们打印下它的类型
[root@linuxea.com /opt/Golang/work3]# cat error2.go
package main
import "fmt"
func main(){
e := fmt.Errorf("Error: %s","division by zero")
fmt.Printf("%T,%vn",e,e)
}
运行
[root@linuxea.com /opt/Golang/work3]# go run error2.go
*errors.errorString,Error: division by zero
2.延迟执行defer
在很多时候,不管程序异常或者正常,我们都希望它执行一些代码。就需要延迟执行
- defer
defer会在函数退出的时候执行。
- 示例
打印两个语句,分别用defer和不用defer。如下:
通常,defer会跟上一个匿名函数调用
defer func(){
fmt.Println("defer")
}()
我们在加上一个fmt.Println("main")
package main
import "fmt"
func main(){
defer func(){
fmt.Println("defer")
}()
fmt.Println("main")
}
运行
[root@linuxea.com /opt/Golang/work3]# go run defer.go
main
defer
可以发现,main先被打印,而后再打印的defer
- 多个defer
如果此刻有多个defer,打印的顺序将会是从后往前执行,如下:
- 示例
分别打印defer one
,defer two
和main
package main
import "fmt"
func main(){
defer func(){
fmt.Println("defer two")
}()
defer func(){
fmt.Println("defer one")
}()
fmt.Println("main")
}
运行
[root@linuxea.com /opt/Golang/work3]# go run defer1.go
main
defer one
defer two
这遵循栈规则,先进后出。或者说defer是从下往上执行的顺序。
3.panic与recover错误处理
go语言提供panic和recover函数用于处理运行时的错误,当调用panic抛出错误,中断原有的流程控制,常用于不可修复性错误。recover函数用于终止错误处理流程,仅在defer语句的函数中有效,用于截取错误处理流程,recover只能捕获到最后一个错误
- panic示例
我们在panic前后打印start和end
[root@linuxea.com /opt/Golang/work3]# cat panic.go
package main
import "fmt"
func main(){
fmt.Println("main start")
panic("error")
fmt.Println("main end")
}
运行
[root@linuxea.com /opt/Golang/work3]# go run panic.go
main start
panic: error
goroutine 1 [running]:
main.main()
/opt/Golang/work3/panic.go:5 +0x96
exit status 2
可以看到panic后面的print是没有执行的。在panic处就结束了。
- recover
recover函数一般用于做恢复的,主动处理panic的错误,必须用于defer中。
但是和之前不同的是,使用了recover后,发生错误后返回的是一个panic error
信息
- 示例
recover是string类型的一个error,所以我们可以使用if判断是否等于nil或者不等于nil
如果不等于nil,那说明有错误,就可以抛出错误。这里手动加的panic("the is error")
package main
import "fmt"
func main(){
defer func(){
if err := recover(); err != nil{
fmt.Println(err)
}
}()
fmt.Println("start")
panic("the is error")
fmt.Println("end")
}
运行
[root@linuxea.com /opt/Golang/work3]# go run recover.go
start
the is error
如果没有panic错误,就不会执行recover()
[root@linuxea.com /opt/Golang/work3]# cat recover.go
package main
import "fmt"
func main(){
defer func(){
if err := recover(); err != nil{
fmt.Println(err)
}
}()
fmt.Println("start")
fmt.Println("end")
}
运行
[root@linuxea.com /opt/Golang/work3]# go run recover.go
start
end
- 示例2
在其他函数中也可以直接这样抓取panic错误,如下:
func test(){
defer func(){
if err := recover(); err != nil{
fmt.Println(err)
}
}()
panic("the test error")
}
或者返回一个error信息
首先定义一个error返回值,如果发生panic错误,就通过recover将值赋值给err,通过return返回
func test() (err error) {
defer func(){
if er := recover(); er != nil{
err = fmt.Errorf("%v",er)
}
}()
panic("the test error")
return
}
而后在main中,因为test有返回值,这里需要as接收,而后打印即可。
func main(){
as := test()
fmt.Println(as)
}
如下:
package main
import "fmt"
func test() (err error) {
defer func(){
if er := recover(); er != nil{
err = fmt.Errorf("%v",er)
}
}()
panic("the test error")
return
}
func main(){
as := test()
fmt.Println(as)
}
运行
[root@linuxea.com /opt/Golang/work3]# go run testerr.go
the test error