Issue
I’m trying to build a factory that constructs implementations of a given interface. To make adding new implementations of that interface easier, I’m trying to have the various implementations auto-register their constructors with the factory at init()
time, but I can’t seem to figure out if it’s possible to make something like this.
Here’s a very simple thing that I thought would work, but doesn’t (from the playground: https://go.dev/play/p/D-gmcpX3_BE). It gives the error:
cannot use BarConstructor (value of type func() bar) as type FooConstructor in argument to tester
package main
import "fmt"
// foo is an interface that just has a single function
type foo interface {
f() string
}
// bar is a type that implements foo
type bar struct {
}
func (b bar) f() string {
return "baz"
}
// BarConstructor creates bars
func BarConstructor() bar {
return bar{}
}
// FooConstructor is a function type that returns foo interfaces
type FooConstructor func() foo
// take a thing that constructs foos
func tester(constructor FooConstructor) {
f := constructor()
fmt.Println(f.f())
}
func main() {
// Why is BarConstructor not the right type?
tester(BarConstructor)
}
Solution
BarConstructor
is a function that returns bar
, but the tester
needs a function that returns foo
. Even though bar
implements foo
, the signatures don’t match, so the argument is not accepted.
Go type system treats all types as distinct types based on their name/signature.
You have a few options:
- Declare the BarConstructor to return foo
- Write an adapter func:
tester(func() foo {return BarConstructor()})
Answered By – Burak Serdar
Answer Checked By – David Marino (GoLangFix Volunteer)