I tried to append different functions that can be represented with the same interface. Functions return different objects but same interface. It failed with the error cannot use Test (value of type func() *Dog) as func() Animal value in argument to append (typecheck)
What should I do? Thanks in advance!
package main
type Dog struct {
Word string
}
type Cat struct {
Word string
}
func (d *Dog) Say() string {
return d.Word
}
func (c *Cat) Say() string {
return c.Word
}
type Animal interface {
Say() string
}
func main() {
funcs := []func() Animal{}
funcs = append(funcs, Test) // error| cannot use Test (value of type func() *Dog) as func() Animal value in argument to append (typecheck)
}
func Test() *Dog {
return &Dog{Word: "dog"}
}
func Test2() *Cat {
return &Cat{Word: "cat"}
}
Change your functions to have Animal
as their return type. func() *Dog
is not convertible to func() Animal
, they are two separate data types.
Similar to how you can pass, say, int
as interface{}
, but not []int
as []interface{}
The problem is that func () *Dog
cannot converts to func() Animal
. If you don't wanna use reflection, you have to change the "funcs" type to []interface{}
then cast each element of the slice into func() *Dog
and simply call it, like this:
package main
import "fmt"
type Dog struct {
Word string
}
type Cat struct {
Word string
}
func (d *Dog) Say() string {
return d.Word
}
func (c *Cat) Say() string {
return c.Word
}
type Animal interface {
Say() string
}
func main() {
var funcs []interface{}
funcs = append(funcs, Test)
fmt.Println(funcs[0].(func() *Dog)().Say()) // prints "dog"
}
func Test() *Dog {
return &Dog{Word: "dog"}
}
func Test2() *Cat {
return &Cat{Word: "cat"}
}
The slice element and functions have different return types. Use anonymous functions to convert the function return values to the slice element return type.
funcs = append(funcs,
func() Animal { return Test() },
func() Animal { return Test2() })
for _, f := range funcs {
fmt.Println(f().Say())
}
Another option is to use the reflect package to call the function and convert the result to an Animal.
func makeAnimal(f interface{}) Animal {
// This function assumes that f is a function
// that returns a value that satisfies the
// Animal interface.
result := reflect.ValueOf(f).Call(nil)
return result[0].Interface().(Animal)
}
Use it like this:
funcs := []interface{}{}
funcs = append(funcs, Test, Test2)
for _, f := range funcs {
a := makeAnimal(f)
fmt.Println(a.Say())
}