英文:
Golang packages and using variables across packages
问题
我有点想知道这里的最佳实践是什么。
我有一个应用程序,有几个子包,其中一些需要访问我在主包中的日志记录器,因为我使用了一个带有颜色和时间戳等自定义日志记录器。
实现这一点的唯一方法是像这样注入吗?(假设Handler在名为command的子包中)
type Handler struct {
logger logging.Logger
}
func NewHandler(logger logging.Logger) Handler {
return Handler{
logger: logger,
}
}
handler := command.NewHandler(logger)
我对此的问题是,测试变得很麻烦,因为我必须为测试模拟日志记录器。
我考虑过只返回应该记录的错误,并让主包处理它们,但我想异步运行一些函数,像这样
go handler.HandleMessage(msg)
所以我不知道如何处理异步函数的错误,或者是否可能。
所以有没有最佳实践来实现我想要的?
英文:
So I'm kinda wondering what the best practice is here.
I have an application with several subpackages, some require access to the logger I have in the main package, because i use a custom logger with colors and timestamps etc.
Is the only way of accomplishing this by injecting it like so? (Assuming Handler is in a subpackage called command)
type Handler struct {
logger logging.Logger
}
func NewHandler(logger logging.Logger) Handler {
return Handler{
logger: logger,
}
}
handler := command.NewHandler(logger)
This issue I have with this is that testing becomes annoying since I have to mock the logger for tests.
I thought about just returning errors that should be logged and let the main package deal with them, but I'd like to run some function async like so
go handler.HandleMessage(msg)
So idk how to handle errors from asynchronous functions or if its even possible.
So is there a best practice to do what I want?
答案1
得分: 2
关于这个问题,我有几点想法:
- 在我看来,注入资源(logger)是最好的方法。直接引用全局变量当然也是可行的,但会使你的代码难以修改。
- 如果 logging.Logger 是一个具体类型,你可以使其在为 nil 时正常工作,从而允许你在测试中跳过初始化。
- 你绝对可以在异步调用中处理错误。
关于最后一点,你可以使用匿名函数在调用点添加额外的错误处理:
go func() {
err := handler.HandleMessage(msg)
// 在这里处理错误/记录日志
}()
如果你能够将错误有意义地传递给发起调用的调用点,那么我每次都更喜欢这样做。但请记住,当从 HandleMessage() 返回时,你仍然在一个单独的 goroutine 中运行。
英文:
A few thoughts on this:
- Injecting the resource (logger) is the best way to do this in my opinion. Directly referencing a global variable is certainly possible, but makes your code hard to change.
- If you logging.Logger is a concrete type then you can make it work when nil, so allowing you to skip initialisation in your tests.
- You absolutely can handle your errors in async calls.
On this last point you can use anonymous functions to add additional error handling at the calling site:
go func() {
err := handler.HandleMessage(msg)
// err handling / logging here
}()
If you can pass errors up meaningfully to the calling site that initiated the call then I prefer to do this every time. You do need to bear in mind that you are still running in a separate goroutine when you come back from HandleMessage().
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论