0

I am trying to create a function which takes in a map as a parameter, where the map uses string keys but the values can be ANY type.

How do I make this work in go? I tried using map[string]interface{} as the parameter type to the function but that does not seem to work for example when passing in a map[string]int as an argument.

Any explanations as to what is the problem with this approach and if there is a way to achieve this in go?

3
  • 1
    Next year, if generics are added to Go 1.18, you should be able to do what you want (go2goplay.golang.org/p/VxeWRaAPE8k). But until then, you have to convert a map[string]int before passing it as map[string]interface{}. Alternatively your function could accept just interface{} and use reflect to do whatever it needs to do with the map. Commented Oct 21, 2021 at 2:48
  • Step 1. Start by understanding that interface{} doesn't mean "any type". (It means literally interface{}. Step 2: Decide if you want to A) redesign, B) fall back to (ugly) reflection or C) wait for parametric polymorphism (vulgo "generics" ) in Go 1.18. I'd recommend 1 + 2A. Commented Oct 21, 2021 at 5:53
  • @mkopriva that is exactly what I was hoping to do - well looks like I gotta wait and use the method you mentioned in the meanwhile Commented Oct 26, 2021 at 5:49

1 Answer 1

3

If a function parameter is of type map[string]interface{} then you need to pass it a map[string]interface{} (and map[string]int is not map[string]interface{}).

This is a common issue and is covered in the FAQ (this focuses on slices but the same principal applies to maps).

The best approach really depends upon what you are trying to accomplish. You can do something like the following (playground):

package main

import (
    "fmt"
)

func main() {
    v := make(map[string]interface{})

    v["blah"] = 3
    test(v)

    v["panic"] = "string"
    test(v)

}

func test(in map[string]interface{}) {
    var ok bool
    converted := make(map[string]int)
    for k, v := range in {
        converted[k], ok = v.(int)
        if !ok {
            panic("Unexpected type in map")
        }
    }
    fmt.Println(converted)
}

or accept an interface{} which allows anything to be passed in (playground):

package main

import (
    "fmt"
)

func main() {
    v := make(map[string]int)
    v["blah"] = 3
    test(v)

    w := make(map[string]string)
    w["next"] = "string"
    test(w)

    x := make(map[string]bool)
    x["panic"] = true
    test(x)

}

func test(in interface{}) {
    switch z := in.(type) {
    case map[string]int:
        fmt.Printf("dealing with map[string]int: %v\n", z)
    case map[string]string:
        fmt.Printf("dealing with map[string]string: %v\n", z)
    default:
        panic(fmt.Sprintf("unsupported type: %T", z))
    }
    // You could also use reflection here...
}
Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.