为什么有些包声明了两个相同的函数,唯一的区别是一个被导出而另一个不是,但导出的只返回非导出函数,如下所示:
func Foo() {
return foo()
}
func foo() {
log.Println("Hello")
}
为什么不将日志移动到导出的函数中并删除额外的行?显然有一个原因,但如果你可以在任何地方使用导出的那个,我真的没有看到。谢谢!
生产中使用的示例here
答案 0 :(得分:4)
你提到了几个例子。第一个例子(https://github.com/yohcop/openid-go/blob/master/verify.go#L11-L13):
func Verify(uri string, cache DiscoveryCache, nonceStore NonceStore) (id string, err error) {
return verify(uri, cache, urlGetter, nonceStore)
}
您可以看到未导出的verify
函数需要额外的urlGetter
参数。这可能是此软件包的客户端无法或不应提供的内容。导出的函数确定包的客户端可以/应该如何使用它;非导出函数的签名反映了执行任何业务逻辑verify
所需的依赖关系。
第二个例子(https://github.com/golang/oauth2/blob/master/oauth2.go#L259-L266):
func StaticTokenSource(t *Token) TokenSource {
return staticTokenSource{t}
}
// staticTokenSource is a TokenSource that always returns the same Token.
type staticTokenSource struct {
t *Token
}
这限制了客户端如何构造staticTokenSource
:只有一种方法可以通过StaticTokenSource
构造函数来完成它,并且不能通过struct literal直接完成。由于许多原因,这可能是有用的,例如,输入验证。在这种情况下,您希望知道客户端不能改变对象上的t
字段的安全性,并且为了做到这一点,您将保留t
字段未导出。但是当它被取消导出时,客户端将无法直接构造结构文字,因此您必须提供构造函数。
通常,当您可以限制访问,构造或变异的方式时,它会使您的代码更容易推理。 Golang包为您提供了一种很好的机制来封装业务逻辑模块。考虑软件的概念组件以及它们的接口应该是什么,这是一个好主意。什么真的需要暴露给消耗给定组件的客户端代码?只有真正需要出口的东西应该是。
进一步阅读:Organizing Go code