英文:
How to share service connections in Golang
问题
我是你的中文翻译助手,以下是翻译的内容:
我对Go语言还不熟悉,正在查看Go语言的elastic库,在入门示例中,它说:“通常为应用程序创建一个客户端。”
这是什么意思?你是在main
函数中创建一个客户端,然后以某种方式将其传递给带有context的函数吗?你是创建一个全局变量并将其分配给客户端,像这样吗?
var (
client *elastic.Client
)
func a() {
client.Search()
}
func main() {
c, err := elastic.NewClient()
client = c
}
英文:
I'm new to Go and looking at this the elastic library for go and in the Getting Started example it says "You typically create one client for your app."
What does that mean? Do you create a client in the your main
function and somehow pass it to the functions with context? Do you create a global variable and assign it to the client, like this?
var (
client *elastic.Client
)
func a() {
client.Search()
}
func main() {
c, err := elastic.NewClient()
client = c
}
答案1
得分: 2
这涉及到了一个在Go语言中有点有争议的话题:依赖注入。
与其他一些语言不同,我们通常不相信使用复杂的IOC容器、XML配置和基于反射的工具来处理这种情况。我只是遵循一些简单的原则:
-
应用程序包和组件应该明确地传递它们所依赖的所有内容。最好使用接口类型。如果我的
web
包需要一个数据库连接和一个elastic客户端,它可以有一个类似于Serve(addr string, db database.DB, client *elastic.Client)
的函数,其中DB
是我的应用程序的数据库的接口类型。 -
main
函数的工作主要是读取配置,创建所有共享组件,并将它们传递给各个组件:func main(){ var config = readConfig() //flags, json, whatever var elastic = elastic.NewClient(config.whatever) var db = database.New(config.Connectionstring) //现在启动应用程序组件 web.Serve(config.Addr, db, elastic) }
我发现这种模式有助于保持我的包分离但又可以互操作。我尽量避免在包级别使用变量,特别是对于需要在运行时更改的内容。
英文:
This gets into a topic that is kinda controversial in go: dependency injection.
Unlike some other languages, we don't usually believe in complicated IOC containers, xml config, and reflection based tools for this kind of thing. I merely follow a few simple principles:
-
Application packages and components should have all of their dependencies passed to them explicitly. Preferably as an interface type. If my
web
package needs a database connection, and an elastic client, it may have a function likeServe(addr string, db database.DB, client *elastic.Client)
whereDB
is an interface type for my application's db. -
The job of
main
is essentially to read configuration, create all shared components, and pass them to the various components:func main(){ var config = readConfig() //flags, json, whatever var elastic = elastic.NewClient(config.whatever) var db = database.New(config.Connectionstring) //now start app components web.Serve(config.Addr, db, elastic) }
I find this pattern helps keep my packages separate yet inter-operable. I try to avoid package level variables for anything that needs to change from run to run.
答案2
得分: 1
我会创建一个特殊类型来保存这些对象。
type AppFactory struct {
Client *http.Client
DatastoreClient *datastore.Client
FileStorage FileStorage
DB DB
}
或者你可以使用context.Context
。
type key int
const clientKey key = 0
func NewContext(ctx context.Context, client *elastic.Client) context.Context {
return context.WithValue(ctx, clientKey, client)
}
func ClientFromContext(ctx context.Context) *elastic.Client {
client := ctx.Value(clientKey).(*elastic.Client)
return client
}
个人而言,我会使用context.Context
,因为它是更通用的解决方案。
我认为使用全局变量不是一个好主意。很快它可能会成为一个问题。
英文:
I would create special type that holds these objects.
type AppFactory struct {
Client *http.Client
DatastoreClient *datastore.Client
FileStorage FileStorage
DB DB
}
or you can use context.Context
type key int
const clientKey key = 0
func NewContext(ctx context.Context, client *elastic.Client) context.Context {
return context.WithValue(ctx, clientKey, client)
}
func ClientFromContext(ctx context.Context) *elastic.Client {
client := ctx.Value(clientKey).(*elastic.Client)
return client
}
Personally, I would use context.Context because it is more universal solution.
I don't think it is a good idea to use global variables.
Very quickly it can become a problem.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论