Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

generic map value

I have run into this problem a few times when wanting to use keys of maps in a similar way but the values in the maps are different. I thought I could write a function that takes the key type I want with interface{} as the value type but it doesn't work.

func main() {
    mapOne := map[string]int
    mapTwo := map[string]double
    mapThree := map[string]SomeStruct

    useKeys(mapOne)
}
func useKeys(m map[string]interface{}) {
    //something with keys here
}

Not sure if there is an elegant way to do this I just feel waist full rewriting simple things for different values.

like image 813
mvryan Avatar asked Sep 10 '14 18:09

mvryan


People also ask

What is a generic map?

A generic map gives the value to a generic. Usually given in an instance but can also appear in a configuration. The values can be given via positional association or via named association. Use of named association is advised to improve readability and reduce the risk of making errors.

What is generic map in Java?

What is Generic Map and how is it different from the term HashMap? The term generic simply is the idea of allowing the type (Integer, Double, String, etc. or any user-defined type) to be the parameter to methods, class, or interface. For eg, all the inbuilt collections in java like ArrayList, HashSet, HashMap, etc.

How do you collect a value from a map?

HashMap get() Method in Java util. HashMap. get() method of HashMap class is used to retrieve or fetch the value mapped by a particular key mentioned in the parameter.

Is map a generic interface Java?

Java has provided generic support in Map interface.


2 Answers

Go 1.18

You can write a function with type parameters (generic) for this:

func useKeys[V any](m map[string]V) V {
    return m["foo"]
}

And use it as:

func main() {
    m1 := map[string]int{"foo": 1}
    m2 := map[string]float64{"foo": 4.5}
    m3 := map[string]*SomeStruct{}

    fmt.Println(useKeys(m1))
    fmt.Println(useKeys(m2))
    fmt.Println(useKeys(m3))

}

As you can see, the type parameter V unifies with the map value, so that you can explicitly force callers of useKeys to pass maps whose keys are string only.

You can see this on the GoTip Playground: https://gotipplay.golang.org/p/epFA2_9u5l5

like image 143
blackgreen Avatar answered Sep 30 '22 16:09

blackgreen


Though maps and slices in go are generic themselves, they are not covariant (nor could they be, since interfaces aren't generics). It's part of working with a language that doesn't have generics, you will have to repeat some things.

If you really just need to get the keys of any old map, you can use reflection to do so:

func useKeys(m interface{}) {
    v := reflect.ValueOf(m)
    if v.Kind() != reflect.Map {
        fmt.Println("not a map!")
        return
    }

    keys := v.MapKeys()
    fmt.Println(keys)
}
like image 35
JimB Avatar answered Sep 30 '22 15:09

JimB