Function types that return interfaces in go

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:

  1. Declare the BarConstructor to return foo
  2. Write an adapter func:
tester(func() foo {return BarConstructor()})

Answered By – Burak Serdar

Answer Checked By – David Marino (GoLangFix Volunteer)

Leave a Reply

Your email address will not be published.