为什么有些包声明了两个相等的函数,唯一的区别是一个是导出的,另一个不是,但是导出的只是返回非导出的函数,如下所示:
func Foo() {
return foo()
}
func foo() {
log.Println("Hello")
}
Run Code Online (Sandbox Code Playgroud)
为什么不将日志移到导出的函数中并去掉多余的行?显然是有原因的,但如果你可以在任何地方使用导出的一个,我真的看不到一个。谢谢!
实施例在这里它在生产中使用
你提到了几个例子。第一个例子(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)
}
Run Code Online (Sandbox Code Playgroud)
您可以看到未导出的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
}
Run Code Online (Sandbox Code Playgroud)
这限制了客户端如何构造staticTokenSource
: 只有一种方法可以通过StaticTokenSource
构造函数来完成,并且不能直接通过结构体来完成。出于多种原因,这可能很有用,例如输入验证。在这种情况下,您希望知道客户端无法改变t
对象上的字段的安全性,为了做到这一点,您不t
导出该字段。但是当它未导出时,客户端将无法直接构造 struct 文字,因此您必须提供一个构造函数。
一般来说,它使您的代码更容易推理何时可以限制事物的访问、构造或变异方式。Golang 包为您提供了一种很好的机制来封装业务逻辑模块。考虑软件的概念组件以及它们的接口应该是什么是个好主意。什么真正需要暴露给使用给定组件的客户端代码?只有真正需要导出的东西才应该是。
进一步阅读:组织 Go 代码