Reputation: 11153
There are some generated code I cannot change. They have the general structure like below:
// These structures & methods I cannot change
type NotMyStruct struct {
EmbeddedCaller
}
type EmbeddedCaller struct {
foobar string
}
func (_embeddedCaller *EmbeddedCaller) DoStuff() string {
return "ABC"
}
func NewNotMyStruct() *NotMyStruct {
return &NotMyStruct{
EmbeddedCaller{"blah"},
}
}
The general pattern of the generated code is 1) a parent struct + an embedded struct 2) a method on the embedded struct and 3) a New method that creates the struct.
I have a number of these generated "contracts" and they all have different types, ie NotMyStruct1 NotMyStruct2 etc etc. The embedded structs are all different types as well, ie EmbeddedCaller1, EmbeddedCaller2 etc.
However they all have the same method DoStuff with the same return value. What I would like to do is create a map of some id to the New functions then iterate over each of these and call the DoStuff method. However my code does not compile. it would look something like this if it compiled:
type MyDoStuffInterface interface {
DoStuff() string
}
var instantiations map[string]func()*MyDoStuffInterface{
"1": NewNotMyStruct, //<-- does not compile here because *MyDoStuffInterface doesn't match *NotMyStruct
...
}
for id, instantiationFunc := range instantiations {
instance := instantiationFunc()
instance.DoStuff()
}
Is it possible to do what I'm trying to do? If so how? If not, what is the easiest way to keep things dry?
Upvotes: 0
Views: 67
Reputation: 58271
First, you need to replace *MyDoStuffInterface
with MyDoStuffInterface
. Pointers to interfaces do have their uses, but nearly all of the time they aren't needed (or correct).
Second, the type of your function (func()*NotMyStruct
) doesn't match func()MyDoStuffInterface
. (People more experienced in types than me might say that function types in go aren't covariant or something like that).
The best way to solve this second problem is to use a wrapper function that has the correct type. (An alternative is to avoid the type system and use interface{}
for your function type and use run-time reflection to call your function).
Here's a full compiling example (playground link). (I had to change your instantiations
variable a little because the syntax for initializing a map wasn't correct.)
package main
type NotMyStruct struct {
EmbeddedCaller
}
type EmbeddedCaller struct {
foobar string
}
func (_embeddedCaller *EmbeddedCaller) DoStuff() string {
return "ABC"
}
func NewNotMyStruct() *NotMyStruct {
return &NotMyStruct{
EmbeddedCaller{"blah"},
}
}
type MyDoStuffInterface interface {
DoStuff() string
}
func main() {
var instantiations = map[string](func() MyDoStuffInterface){
"1": func() MyDoStuffInterface { return NewNotMyStruct() },
}
for _, instantiationFunc := range instantiations {
instance := instantiationFunc()
instance.DoStuff()
}
}
Upvotes: 5
Reputation:
Use the following map:
var instantiations = map[string]func()MyDoStuffInterface{
"1": func() MyDoStuffInterface {
return NewNotMyStruct()
},
}
Some notes:
The anonymous "adaptor" function is required because NewNotMyStruct()
returns a *NotMyStruct
, not a MyDoStuffInterface
.
Do not use a pointer to an interface. They are not needed.
Upvotes: 1