Search code examples
gopluginsreflectioncode-generation

How to convert interface to another interface which it implements?


In short - I would like to be able to cast an interface type whose underlying type implements a specific interface to that specific interface.

I am using the plugin package to lookup a New function which looks like so (I have many others the same):

func NewDomainPrimaryKey() any { return DomainPrimaryKey{} }

(This is generated at run-time so I can't just reference it as DomainPrimaryKey)

My lookup and call is like so:

                plugin, err := plugin.Open("my-plugin")
                if err != nil {
                    return err
                }

                symGet, err := plugin.Lookup("New" + pluginName)
                if err != nil {
                    return err
                }

                newGenModel, ok := symGet.(func() any)
                if !ok {
                    return errors.New("unexpected type from module symbol")
                }

                anyGenModel := newGenModel()
                genModel, ok := anyGenModel.(GenModel) // **this is where the problem is
                if !ok {
                    return errors.New("unexpected type from module symbol")
                }

                genModelInstance := genModel.Get()

In the above I am trying to cast 'anyGenModel' (an interface) to the 'GenModel' interface which it implements, however, this doesn't work.

I am certain it implements this interface because when I do the following, I get no errors.

type GenModel interface {
    Get() any
    TableName() string
}

var _ GenModel = (*DomainPrimaryKey)(nil) // this doesn't complain

How can I do this? I found this article which I don't think is what I am looking for but seems similar.

Thanks in advance for any help on this - this has become a real blocker for me.


Solution

  • If the underlying type implements both interfaces, this is very straightforward:

    package main
    
    import "fmt"
    
    type IFace1 interface {
        DoThis()
    }
    
    type IFace2 interface {
        DoThat()
    }
    
    type impl struct{}
    
    func (i *impl) DoThis() {
        fmt.Println("I implement IFace1")
    }
    
    func (i *impl) DoThat() {
        fmt.Println("I implement IFace2")
    }
    
    func GetIFace1() IFace1 {
        return &impl{}
    }
    
    func main() {
        i1 := GetIFace1()
    
        i1.DoThis()
    
        i2 := i1.(IFace2)
    
        i2.DoThat()
    }
    

    playground

    If your code is not working, then I would begin by questioning your assertion that the underlying type of anyGenModel actually implements GenModel and work from there.