零并不总是零

零并不总是零


“什么?在这里写什么?” 你问。 现在,我将其全部放下。


当我开始学习语言时,我认为我不会遇到这种狭case的情况。 修改可迭代的集合也是不合理的。


例如:

func Foo() error { var err *os.PathError = nil return err } func main() { err := Foo() fmt.Println(err) // <nil> fmt.Println(err == nil) // false } 

哇!


什么是接口?

转到go runtime / runtime2.go软件包文件,请参阅:


 type itab struct { // 40 bytes on a 64bit arch inter *interfacetype _type *_type ... } 

接口存储接口的类型和值本身的类型。


在AND值和类型为nil的情况下,任何接口的值(不仅是错误)都是nil。


Foo函数返回类型为* os.PathError的nil,我们将结果与类型为nil的nil进行比较,由此得出它们的不等式。


也许很多人都知道这一点,但是很少有人思考如何在实践中融入它。


我的例子

 type Response struct { Result ResponseResult `json:"result,omitempty"` Error *ResponseError `json:"error,omitempty"` } type ResponseError struct { Message string `json:"message"` } func (e *ResponseError) Error() string { return e.Message } ... func (s *NotificationService) NotifyIfError(w *ResponseWriter) error { ... var res handlers.Response _ = json.Unmarshal(body, &res) if res.Error == nil { return } return s.NotifyError(err) } 

响应总是有结果或错误。


如果有错误,我们会在必要时通过通知服务将其发送。
在服务内部,将调用Error方法,并且由于我们的值为nil,我们会感到恐慌。


怎么办

严格返回接口类型的接口。


如果发生错误-错误类型。


  • 添加类型错误声明

 func (s *NotificationService) NotifyIfError(w *ResponseWriter) error { ... var res Response _ = json.Unmarshal(body, &res) var err error = res.Error return s.NotifyError(err) } 

令我惊讶的是,该技术也不起作用。


事实证明,当为err变量赋值时,我们还将有关类型的初始信息传递给它,该信息不是nil。


  • 让我们尝试从接口类型获取源类型并检查其值。

 func (s *NotificationService) NotifyIfError(w *ResponseWriter) error { ... if e, ok := err.(*ResponseError); ok && e == nil { return s.NotifyError(err) } return nil } 

是的,这项技术有效。


但是,老实说,我们负担不起检查将要传输的所有错误类型。


可能是数据库驱动程序中的所有错误,我们所有的内部错误以及其他垃圾。


我看到的最合理的选择是:

 func (s *NotificationService) NotifyIfError(w *ResponseWriter) error { var err error ... var res Response _ = json.Unmarshal(body, &res) if res.Error != nil { return s.NotifyError(err) } return nil } 

首先,我们声明了一个类型为error的变量,因为它的值和类型均为nil。
在将类型和值传递给此变量之前,让我们检查类型及其在nil上的值。


这将使我们不要惊慌失措。


最后

您可以更进一步,使用Response,OptionalError或ErrorOrNil类型实现“可选”错误,如下所示:


 func (r *Response) ErrorOrNil() error { if r.Error == nil { return nil } return r.Error } 

注意事项

Go Wiki注释中,代码回顾是该主题中有关接口注释:而是返回一个具体的类型,并让使用者模拟生产者实现。


我注意到上面的舞蹈与这无关。


当您知道要返还利息时,我的便笺使您不必惊慌,并且在出现错误的情况下,您始终希望返回界面。


但是,如果您有能力返回某个类型,则将其返回。


参考文献

内部人


我是

领英
电报
推特
Github

Source: https://habr.com/ru/post/zh-CN449714/


All Articles