英文:
Type-assertion panic
问题
我想在我的代码中应用依赖注入,所以我将它的每个部分都创建为一个服务。
type BaseService struct {
Config config.Container
SQL *gorm.DB
Mongo *mgo.Session
Logger logger.Logger
}
type BaseInterface interface {
Set(c config.Container, sq *gorm.DB, m *mgo.Session, l logger.Logger) BaseInterface
}
func (s BaseService) Set(c config.Container, sq *gorm.DB, m *mgo.Session, l logger.Logger) BaseInterface {
s.Config = c
s.SQL = sq
s.Mongo = m
s.Logger = l
return s
}
func NewSetupService(c config.Container, s *gorm.DB, m *mgo.Session, l logger.Logger) SetupService {
return SetupService{}.Set(c, s, m, l).(SetupService)
}
...
...
这里有一个BaseService
,每个服务都扩展它,如下所示:
type SetupService struct {
BaseService
}
type SetupInterface interface {
Do()
}
func (s SetupService) Do() {
mongo := s.Mongo.Clone()
defer mongo.Close()
mongoDB := mongo.DB(s.Config.Database.Mongo.DB)
...
...
但是当我调用NewSetupService
函数时,我得到了一个不清楚的恐慌。基本上,我创建了一个SetupService{}
并调用了该结构的Set
函数,我是对的吗?那么为什么我会得到这个恐慌:
panic: interface conversion: api.BaseInterface is api.BaseService, not api.SetupService [recovered]
panic: interface conversion: api.BaseInterface is api.BaseService, not api.SetupService
英文:
I would like to apply Dependency injection on my code so I create every part of it as a service.
type BaseService struct {
Config config.Container
SQL *gorm.DB
Mongo *mgo.Session
Logger logger.Logger
}
type BaseInterface interface {
Set(c config.Container, sq *gorm.DB, m *mgo.Session, l logger.Logger) BaseInterface
}
func (s BaseService) Set(c config.Container, sq *gorm.DB, m *mgo.Session, l logger.Logger) BaseInterface {
s.Config = c
s.SQL = sq
s.Mongo = m
s.Logger = l
return s
}
func NewSetupService(c config.Container, s *gorm.DB, m *mgo.Session, l logger.Logger) SetupService {
return SetupService{}.Set(c, s, m, l).(SetupService)
}
...
...
There is the BaseService and every service extend it as the follow:
type SetupService struct {
BaseService
}
type SetupInterface interface {
Do()
}
func (s SetupService) Do() {
mongo := s.Mongo.Clone()
defer mongo.Close()
mongoDB := mongo.DB(s.Config.Database.Mongo.DB)
...
...
But when I call the NewSetupService function I got a panic which is not clear for me. Basically I create a SetupService{} and call the Set function of this struct, am I right? Then why I got this panic:
panic: interface conversion: api.BaseInterface is api.BaseService, not api.SetupService [recovered]
panic: interface conversion: api.BaseInterface is api.BaseService, not api.SetupService
答案1
得分: 3
当你从函数中返回一个BaseInterface
时,引用的类型实际上是BaseInterface
而不是SetupService
。虽然SetupService
确实满足BaseInterface
,但当你进行类型转换时,类型信息会丢失。
你可以这样做:
func (s SetupService) Set() SetupService {
s.BaseService.Set()
return s
}
需要注意的是,你没有使用指针,所以每次方法调用都会复制对象,状态变化不会被保留。你可能想要将这些代码替换为:
func (s *SetupService) ...
更新: 为什么不避免返回Set的结果呢?
s := SetupService{}
s.Set(...)
return s
英文:
When you return a BaseInterface
from a function, the type of the reference is actually BaseInterface
and not SetupService
. It is true that SetupService
does satisfy BaseInterface
, but that type information is lost when you cast.
What you could do is this:
func (s SetupService) Set() SetupService {
s.BaseService.Set()
return s
}
One thing to note though is that you're not using pointers, so each method call copies the object and state mutations are not preserved. You might want to replace these:
func (s SetupService) ...
With these:
func (s *SetupService) ...
Update: Why not just avoid returning the result of Set here?
s := SetupService{}
s.Set(...)
return s
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论