golang 函数四 (错误处理)

100018 · · 1720 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

为了方便实现自定义错误类型,Go语言标准库中将error定义为接口类型。比如:

type聽error聽interface{
聽聽聽聽Error()聽string
}

按照Go语言编程习惯,error总是最后一个函数返回值,并且标准库提供了创建函数,可以方便的创建错误消息的error对象。比如:

func聽divTest(x聽,y聽int)(int,聽error){
聽聽聽聽if聽y聽==聽0{
聽聽聽聽聽聽聽聽return聽0,聽errors.New("division聽by聽zero")聽//创建错误消息的error对象
聽聽聽聽}聽聽聽
聽聽聽聽return聽x/y,nil
}
func聽main(){
聽聽聽聽v,聽err聽:=聽divTest(3,0)
聽聽聽聽if聽err聽!=聽nil{
聽聽聽聽聽聽聽聽log.Fatalln(err.Error())
聽聽聽聽}聽聽聽
聽聽聽聽println(v)
}

日常开发中,我们需要根据需求自定义错误类型,可以存放更多的上下文信息,或者根据错误类型做出相应的错误处理。比如:

type聽NegativeError聽struct{
聽聽聽聽x,聽y聽int
}
func聽(NegativeError)Error()string{
聽聽聽聽return聽"negative聽value聽error"
}

type聽MolError聽struct聽{
聽聽聽聽x,聽y聽int
}
func聽(MolError)Error()string{
聽聽聽聽return聽"devision聽by聽zero"
}

func聽molTest(x聽,y聽int)(int,聽error){
聽聽聽聽if聽y聽==聽0{
聽聽聽聽聽聽聽聽return聽0,聽MolError{x,y}
聽聽聽聽}
聽聽聽聽if聽x聽<聽0聽||聽y聽<聽0{
聽聽聽聽聽聽聽聽return聽0,聽NegativeError{x,y}
聽聽聽聽}
聽聽聽聽return聽x%y,nil
}

func聽main(){
聽聽聽聽v,聽err聽:=聽molTest(3,-1)
聽聽聽聽if聽err聽!=聽nil{
聽聽聽聽聽聽聽聽switch聽e聽:=聽err.(type){聽聽聽聽聽//获取错误类型
聽聽聽聽聽聽聽聽聽聽聽聽case聽MolError:
聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽println(e.x,e.y)
聽聽聽聽聽聽聽聽聽聽聽聽case聽NegativeError:
聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽println(e.x,e.y)
聽聽聽聽聽聽聽聽聽聽聽聽default:
聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽println(e)
聽聽聽聽聽聽聽聽}
聽聽聽聽聽聽聽聽log.Fatalln(err.Error())
聽聽聽聽}
聽聽聽聽println(v)
}

与error相比,panic/recover 在应用上更类似于 try/catch 结构化。比如:

func聽panic()聽interface{}聽聽聽
func聽recover()聽interface{}

两者区别:panic 立即中断当前函数处理流程,执行延迟调用。recover在延迟调用中可以捕获并返回panic产生的错误对象,比如:

func聽Myrecover(){
聽聽聽聽if聽err聽:=聽recover();聽err聽!=聽nil{
聽聽聽聽聽聽聽聽log.Fatalln(err)
聽聽聽聽}聽聽聽
}

func聽main(){
聽聽聽聽println("start...")
聽聽聽聽defer聽Myrecover()
聽聽聽聽panic("dead")
聽聽聽聽println("end...")
}
输出:
start...
2017/02/09聽11:24:13聽dead
exit聽status聽1

如果有连续多次调用panic的场景,只有最后一次panic会被recover捕获处理,比如:

func聽Myrecover(){
聽聽聽聽if聽err聽:=聽recover();聽err聽!=聽nil{
聽聽聽聽聽聽聽聽log.Fatalln(err)
聽聽聽聽}聽聽聽
}

func聽main(){
聽聽聽聽defer聽Myrecover()
聽聽聽聽defer聽func(){
聽聽聽聽聽聽聽聽panic("a聽bad聽problem")
聽聽聽聽}()
聽聽聽聽panic("a聽problem")
}
输出:
2017/02/09聽11:31:50聽a聽bad聽problem
exit聽status聽1

recover只有在延迟调用函数中才能得到正常工作,比如:

func聽main()聽{
聽聽聽聽defer聽Myrecover()
聽聽聽聽defer聽log.Println(recover())
聽聽聽聽defer聽println(recover())
聽聽聽聽panic("a聽problem")聽
}
输出:
(0x0,0x0)
2016/11/12聽07:07:54聽<nil>
2016/11/12聽07:07:54聽a聽problem
exit聽status聽1

在日常开发过程中,经常需要进行调试,可以使用函数输出完整的调用栈信息,比如:

func聽Myrecover(){
聽聽聽聽if聽err聽:=聽recover();聽err聽!=聽nil{
聽聽聽聽聽聽聽聽fmt.Println(err)
聽聽聽聽聽聽聽聽debug.PrintStack()
聽聽聽聽聽聽聽聽//log.Fatalln(err)
聽聽聽聽}
}
func聽main(){
聽聽聽聽defer聽Myrecover()
聽聽聽聽panic("a聽problem")
}
输出:
a聽problem
goroutine聽1聽[running]:
runtime/debug.Stack(0xc42002c010,聽0xc42003fe20,聽0x1)
	/root/data/go/src/runtime/debug/stack.go:24聽+0x79
runtime/debug.PrintStack()
	/root/data/go/src/runtime/debug/stack.go:16聽+0x22
main.Myrecover()
	/root/data/gopath/test/panic.go:10聽+0x85
panic(0x48a5e0,聽0xc42000a320)
	/root/data/go/src/runtime/panic.go:458聽+0x243
main.main()
	/root/data/gopath/test/panic.go:16聽+0x8d

日常开发中,只有在系统发生了不可恢复性或无法正常工作的错误可以使用panic,比如端口号被占用、数据库未启动、文件系统错误等,否则不建议使用。

本文出自 “博学于文,约之于礼” 博客,转载请与作者联系!


有疑问加站长微信联系(非本文作者)

本文来自:51CTO博客

感谢作者:100018

查看原文:golang 函数四 (错误处理)

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

1720 次点击  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传