PumpkinSeed
PumpkinSeed

Reputation: 3123

Type-assertion panic

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

Upvotes: 0

Views: 351

Answers (1)

robbrit
robbrit

Reputation: 17960

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

Upvotes: 3

Related Questions