官方 Go 代码审查注释文档中的接口规则说包应该返回具体类型而不是接口。这样做的动机是:
。可以将新方法添加到实现中,而无需进行大量重构。
我接受这可能是一件好事。
但是,如果我正在编写的类型具有依赖项,没有它就无法实现其目的怎么办?如果我导出具体类型,开发人员将能够在没有该依赖项的情况下实例化实例。为了防御性地编写缺少的依赖项的代码,然后我必须在每个方法实现中检查它,如果不存在,则返回错误。如果开发人员在我的文档中错过了不这样做的任何提示,他或她在运行时之前不会了解问题。
另一方面,如果我声明并返回一个包含客户端所需方法的接口,我可以取消导出具体类型并强制使用工厂方法,该方法接受依赖项作为参数并返回接口加错误。这似乎是确保正确使用软件包的更好方法。
我这样想是不是没有正确地进入围棋精神?语言的道德观是,有一个不太完美的封装来为开发人员提供更大的灵活性是可以的吗?
您可能希望开发人员阅读您提供的文档,并且您可以按照您设置的规则依赖他们。是的,懒惰的开发人员会不时地撞头,但开发的过程并非没有学习。一切都不能明确或强制执行,这没关系。
如果你有一个导出的结构类型Example
并且你提供了一个构造函数NewExample()
,这清楚地表明应该使用NewExample()
来构造Example
的值。任何尝试手动构造Example
的人都应该知道必须设置哪些字段才能使其"可操作"。目标始终是使零值完全起作用,但如果无法实现,构造函数是惯用的方式。
这并不少见,标准库中有无数的例子,例如http.Request
、json.Encoder
、json.Decoder
、io.SectionReader
、template.Template
。
您必须确保的是,如果您的包返回结构的值,则必须(应该(正确初始化它们。此外,如果其他人需要传递由他们创建的结构的值,则必须为他们提供一种简单的方法来创建结构(构造函数(的有效值。其他开发人员自己创建的自定义结构值是否"有效",这不应该引起您的关注。