-->

左耳听风_109_108_Go_编程模式错误处理

你好,我是陈浩网名猪耳朵耗子。

错误处理呢一直是编程必须要面对的问题。

错误处理如果做的好的话,代码的稳定性会很好。

不同的语言啊有不同的错误处理的方式。

那购物员也一样,这节课呢我们就来讨论一下购物员的错误处理啊,尤其是那令人抓狂的if, ever不等于new.在正式讨论go代码里满屏的if error不等于new怎么办?这件事儿之前啊,我想先说一说编程中的错误处理。

我们先来说c语言的错误检查。

首先呢我们知道处理错误最直接的方式啊就是通过错误码,那这个呢也是最传统的方式。

在过程式语言中呢,通常都是通过这样的方式来处理错误的。

比如说c语言,那基本上来说呢,它是通过函数的返回值标志是否有错。

然后呢,通过过局的error number变量,加上一个error spring的数组来告诉你为什么出错。

那为什么是这样的设计呢?道理很简单,除了可以共用一些错误,更重要的是啊这其实是一种妥协。

比如说read right open这些函数的返回值啊,其实是返回有业务逻辑的值。

也就是说呢这些函数的返回值啊有两种语义,一种呢是成功的值。

比如说open函数返回的文件,具柄指针还有星,而另一种呢是错误now.那这样的话就会导致调用者并不知道是什么原因出错了,需要去检查error number来获得出错的原因,从而正确的处理错误。

那一般而言这样的错误处理方式在大多数情况下是没什么问题的。

不过呢也有例外的情况,我们来看一下这个c语言的函数a to i这个函数的作用呢是把一个字符串转成整形。

但是呢问题来了,如果一个要转的字符串是非法的,不是数字的格式,比如说ABC啊,或者整形溢出了,那么这个函数应该返问什么呢?出错返回啊,返回什么数都不合理。

因为这样呢会和正常的结果混淆在一起。

比如说如果返回零,那就会和正常的对零字符的返回值啊完全混淆在一起。

那这样呢就无法判断出错的情况了。

你可能会说啊,是不是要检查一下error number呢?啊,按道理说呢应该是要去检查的。

但是呢我们在c九九的规格说明书中呢,可以看到一段描述。

我贴在了文章里。

也就是说啊像a to IA to FA to l或者a to LL这样的函数啊,是不会设置error number的。

而且呢,如果结果无法计算的话,行为是undefined.所以后来呢布lic又给出了一个新的函数strrage to long.那这个函数在出错的时候啊,就会设置全局变量,还有number了。

虽然啊string to log函数解决了a to i函数的问题,但是呢我们还是能感觉到不是很舒服,也不是很自然。

因为这种用返回值加上error number的错误检查方式呢会有些问题。

比如说啊程序员一不小心啊就会忘记检查返回值,从而造成代码的bug,或者说呢函数的接口非常不纯洁,正常的值和错误的值啊混淆在一起,导致语义上有问题。

所以后来有些类库啊,就开始区分这样的事情。

比如说windows的系统调用呢,就开始使用h result的返回来统一错误的返回值。

那这样呢就可以明确函数调用时的返回值啊是成功还是错误。

但这样一来呢,函数的input和output只能通过函数的参数来完成,于是呢就出现了所谓的入参和出参这样的区别。

但是这样呢又使得函数接口中啊参数的语义变得很复杂一些。

函数是入参一些,函数是出参函数接口呢变得复杂了一些,而且呢依然没有解决函数的成功或者失败可以被人为忽略的问题。

而java语言呢使用track catch finally通过使用异常的方式来处理错误。

那其实这个比起c语言的错误处理啊,进了一大步,使用抛异常和抓异常的方式呢,可以让我们的代码有这样一些好处。

首先,函数接口在input和output以及错误处理等方面的语义啊是比较清楚的。

第二,正常逻辑的代码呢可以跟错误处理和资源清理的代码分开,提高了代码的可读性。

第三,异常呢是不能被忽略的。

第四,在面向对象的语言中啊异常是个对象,所以呢就可以实现多态式的catch.最后与状态返回码相比呢,异常捕捉有一个显著的好处,那就是函数可以嵌套调用或者是链式调用。

好了,我们再来说一说构元的错误处理,构元的函数呢支持多返位值。

所以呢我们可以在返回接口中啊,把业务的语义和控制语义啊区分开构元的很多函数啊都会返回result和error两个值。

于是参数上呢基本上就是入参,而返回接口呢把结果和错误分离。

那这样呢就使得函数的接口语义啊比较清晰,而且呢构物圆中的错误参数啊,如果要忽略需要显示的,忽略,用下划线这样的变量来忽略。

另外呢因为返回的error是个接口,所以呢你也可以扩展自定义的错误处理。

那另外啊如果一个函数返回了多个不同类型的error,你可以使用文稿中这样的方式。

我们从代码中呢可以看出购物员的错误处理方式啊,本质上就是返回值检查。

但是它呢也兼顾了异常的一些好处,也就是对错误的扩展。

那接下来呢聊一聊资源的清理,初错之后呢,是需要做资源清理的那不同的编程语言有不同的资源清理的编程模式。

C语言呢使用的是go to faile的方式到一个集中的地方进行清理。

而c加加语言呢一般来说啊使用RAII模式,通过面向对象的代理模式,到需要清理的资源交做一个代理类。

然后呢,在析构函数中解决java语言呢,可以在final类语句块里进行清理。

而构语啊我们使用defer关键词进行清理。

我在文稿里呢提供了一个够远的资源清理的示例。

那听完音频之后呢,你可以看一看这个代码。

那接下来呢就要说到购物员的if error不等于new的代码了。

那这样的代码的确能让人写到to,那么有没有什么好的方式呢?啊,是有的文章里呢就有一段令人崩溃的代码啊,基本上每一句呢都要做if error不等于new的判断。

那要解决这个事儿呢,我们可以用函数式编程的方式。

我们可以看文章中这个例子。

从这段代码中呢,我们可以看到,我们通过使用cloder的方式啊,把相同的代码给抽出来,重新定义一个函数。

那这样大量的if ever不等于new呢,就处理的很干净了。

但是这样呢会带来一个问题,就需要有一个error变量和一个内部的函数,感觉呢还不是很干净,我们能不能再搞得更干净一点呢?从构元中ff IO点scanner函数的实践中呢,我们似乎可以学习到一些东西。

从我贴出来的实践中啊,我们可以看到scanner在操作底层IO的时候啊,那个folloop中啊没有任何的if, error不等于new的情况。

但是退出循环之后呢,有一个scanner点error的检查。

看来呢我使使用了结构体的方式。

那模仿它呀我们就可以对我们的代码进行重构了。

首先呢我定义一个结构体和一个成员函数。

那之前的error变量和抽出来的内部函数包装进来。

那这样呢我们的代码就可以比较干净了。

那有了这个技术呢,我们的流式接口、flint、 interface也就很容易处理了。

那这个技巧呢,你看一下文章里的代码就明白了。

不过呢需要注意的是,它的使用场景呢是有局限的啊,也就只能在对于同一个业务对象的不断操作下,可以简化错误的处理。

那如果是多个业务对象,还得是需要各种if error不等于new的方式。

最后呢多说一句,我们呢还需要包装一下错误,而不是干巴巴的把error返回到上层。

我们需要把一些执行的上下文啊加进来。

那通常来说呢,我们会使用FMT点error f函数来完成这个事儿,比如文章中这样代码。

另外呢在购物员的开发者中啊,更为普遍的做法是将错误包装在另一个错误里,同时呢保留原始的内容。

那当然啊更好的方式呢是通过一种标准的访问方法。

那这样呢我们最好使用一个接口,比如说coder接口中实现cos方法来暴露原始的错误,方便进一步的检查。

那这里呢有一个好消息,这样的代码呢再也不用我们自己写了,有一个第三方的错误库。

对于这个库啊,我无论到哪儿都能看到它的存在。

所以说这个呢基本上来说啊就是事实上的标准了。

那这里呢我给你提供了一个代码示例,那这个错误库的链接啊,我也给你放在了文章里。

最后呢我还给你分享了两篇参考文章。

那听完音频以后啊,你可以点开文中链接看一下。

好了,这节课呢就到这里。

如果你觉得今天的内容啊对你有所帮助,欢迎你帮我分享给更多人。