类型断言恐慌

huangapple go评论82阅读模式
英文:

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

huangapple
  • 本文由 发表于 2017年5月25日 02:55:19
  • 转载请务必保留本文链接:https://go.coder-hub.com/44166470.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定