knipknap
knipknap

Reputation: 6184

Creating a map of functions that return an interface

I have a Go package that has a large number of (auto-generated) models:

Tax2001_1
Tax2001_2
Tax2001_3
...
Tax2020_1

Each is defined like this:

func NewTax2011_1() *Tax2011_1 {
    return &Tax2011_1 { ... }
}

I want to access them depending on a value (timestamp) that is only known at runtime. So I am trying to put the model constructors into a map:

package tax

type TaxModel interface {
  Calculate()
}

var taxModels = make(map[string]func() *TaxModel)

func init() {
  ...
  taxModels["2011_1"] = NewTax2011_1
  taxModels["2011_2"] = NewTax2011_2
  ...
}

The above code is not correct:

cannot use NewTax2011_1 (type func() *Tax2011_1) as type func() *TaxModel in assignment

Any hint how to achieve that?

Upvotes: 1

Views: 50

Answers (2)

Zan Lynx
Zan Lynx

Reputation: 54355

Here's a test I made which seems to work. Looks like you need to not use a pointer to interface. That is what seems to be the problem.


package main

import "fmt"

type Model_1 struct {
        Name string
}

type Model_2 struct {
        Name string
}

func (m *Model_1) Calculate() int64 {
        return 0
}

func (m *Model_2) Calculate() int64 {
        return 0
}

type Model interface {
        Calculate() int64
}

func main() {
        m := make(map[string]func() Model)
        m["test"] = func() Model {
                return &Model_1{Name: "m"}
        }
        fmt.Println(m["test"]().Calculate())
}

Upvotes: 1

Burak Serdar
Burak Serdar

Reputation: 51622

Assuming Tax2011_1 and its friends implement TaxModel interface, you can declare the constructor to return the interface:

func NewTax2011_1() TaxModel {
  return &Tax2011_1{}
}

You should not use an interface pointer:

var taxModels = make(map[string]func() TaxModel)

Then it should work.

If you cannot change the constructors, you can use an adapter function:

func NewTax2011_1() *Tax2011_1 {...}

var taxModels = make(map[string]func() TaxModel)

func init() {
  ...
  taxModels["2011_1"] = func() TaxModel {return NewTax2011_1()}
  taxModels["2011_2"] = func () TaxModel {return NewTax2011_2() }
  ...
}

Upvotes: 3

Related Questions