虽然“错误处理的基本方式是看着办”,但设计程序接口的时候还是有一些常用的原则可以遵循。
发生错误的时候第一件需要考虑的事情是释放资源,比如打开的文件、分配的内存等,发生错误表示函数已经无法在预计的流程下继续处理,这时候可能已经打开了一些资源,需要进行及时的释放,防止因为反复错误导致程序当机。golang 里面的 defer 函数的设计可以以较为优雅的方式进行资源释放,同时保证了函数的内聚性。
是否返回错误需要考虑让调用者如何处理,错误处理不是上报了事,本地处理的好处是简化函数接口,调用者可以进行简单的错误处理判断。假如函数设计者自己都不知道应该如何处理某个错误,那么返回给上层函数后,很可能出现的情况是调用者也不处理这个错误。这种情况可以称之为“虚伪的可靠性”,似乎考虑了很多种情况,并进行了上报,但容易导致大多数的调用者忽略该错误值。
只对不可能的错误报异常,当所有输入条件已经准备妥当,函数还是无法返回正确的数值的时候,最好可以上报为异常,通知上层程序“我已经尽力了,但确实是没办法”。比如通讯处理函数中,输入参数已经是打开确认可以通信的接口,但调用函数时硬件接口断开了,导致通信异常,这时候上报异常可以让函数处理流程简化直观。可以用 try (someread call) … catch (ConnectException) 的方式方便上层应用程序调用。
##后面的话
在阅读 golang 文档的时候,对这个语言在设计时所考虑的一些问题深深着迷。一段时间迷糊后在代码大全里面发现有个章节对防御性编程做了很好的总结,这些讨论算是读后感吧。