error接口


Go语言引入了一个关于错误处理的标准模式,即error接口,该接口的定义如下:
Go 错误处理 - 图1

对于大多数函数,如果要返回错误,大致上都可以定义为如下模式, 将error作为多种返回值中的最后一个,但这并非是强制要求:
Go 错误处理 - 图2

调用时的代码建议按如下方式处理错误情况:
Go 错误处理 - 图3

示例如下:
Go 错误处理 - 图4
Go 错误处理 - 图5

实现Error()方法:
Go 错误处理 - 图6

之后就可以直接返回PathError变量了,如下:
Go 错误处理 - 图7

如果在处理错误时获取详细信息,而不仅仅满足与打印一句错误信息,那就需要用到类型转换知识了:
Go 错误处理 - 图8

defer

Go语言使用defer关键字能简单地解决资源释放问题。如下
Go 错误处理 - 图9

即使其中的Copy函数抛出异常,Go仍然会保证dstFile和srcFile会被正常关闭。
如果觉得一句话干不完清理的工作,也可以使用在defer后加一个匿名函数的做法:
Go 错误处理 - 图10
另外,一个函数中可以存在多个defer语句,因此需要注意的是,defer语句的调用是遵照先进后出的原则,即最后一个defer语句将最先被执行。只不过,当需要为defer语句到底哪个先执行这种细节而烦恼的时候,说明代码架构可能需要调整一下了。

panic()和recover()

Go语言引入了两个内置函数panic()和recover()以报告和处理运行时错误和程序中的错误场景:
Go 错误处理 - 图11
当在一个函数执行过程中调用panic()函数时,正常的函数执行流程将立即终止,但函数中之前使用defer关键字延迟执行的语句将正常展开执行,之后该函数将返回到调用函数,并导致逐层向上执行panic流程,直至所属的goroutine中所有正在执行的函数被终止。错误信息将被报告,包括在调用panic()函数时传入的参数,这个过程被称为错误处理流程。

从panic()的参数类型interface{}得知,该函数接收任意类型的数据,比如整型、字符串、对象等。调用方法很简单:
Go 错误处理 - 图12

recover()函数用于终止错误处理流程。一般情况下,recover()应该在一个使用defer关键字的函数中执行以有效截取错误处理流程。如果没有在发生异常的goroutine中明确调用恢复过程(使用recover关键字),会导致该goroutine所属的进程打印异常信息后直接退出。
Go 错误处理 - 图13
无论foo()中是否触发了错误处理流程,该匿名defer函数都将在函数退出时得到执行。假如foo()中触发了错误处理流程,recover()函数执行将使得该错误处理过程终止。如果错误流程被触发时,程序传给panic函数的参数不为nil,则该函数还会打印详细的错误信息。


Go 错误处理 - 图14