I want to set multiple types for values of hashmap in Golang. I implemented golang generics any, and wrote function that returned map[string]any.
However, after I ran the code, it returned
$ cannot use r.Method (variable of type string) as type T in map literal
What is the correct way of setting multiple types for values of hashmap in Go?
Here's my code
package main
type RequestProperty struct {
Method string
Params []any
Id int
}
func SetRequestProperty[T any](payloadCombine bool) map[string]T {
var p map[string]T
var r = RequestProperty{
Method: "SET_PROPERTY",
Params: []any{"combined", payloadCombine},
Id: 5,
}
// just for test
p = map[string]T{
"method": r.Method, // << Error Here
}
return p
}
func main() {
p := SetRequestProperty(true)
}
[EDIT] This seems to be working though... I don't know why.
package main
type RequestProperty struct {
Method string
Params []any
Id int
}
// delete [T any], map[string]T
// change it to map[string]any
func SetRequestProperty(payloadCombine bool) map[string]any {
var p map[string]any
var r = RequestProperty{
Method: "SET_PROPERTY",
Params: []any{"combined", payloadCombine},
Id: 5,
}
// just for test
p = map[string]any{
"method": r.Method,
}
return p
}
func main() {
p := SetRequestProperty(true)
}
Shouldn't T just act like an alias to type any? Am I misunderstanding something?
CodePudding user response:
Shouldn't T just act like an alias to type any?
No, it shouldn't.
T is a type parameter, not any. It is only constrained by any.
More generally: a type parameter is not its constraint.
Each time a generic function is instantiated, T is assigned a concrete type argument — which satisfies its constraint — and within the function body, map[string]T becomes a map from string to whatever the concrete T is.
p := SetRequestProperty[int](true)
// makes body look like: `var p map[string]int`
// the literal `map[string]int{"method": r.Method}` obviously can't work
Therefore at compile time, the compiler will reject assignments to T that are not compatible with all types in T's type set. The code map[string]T{"method": r.Method} doesn't compile because:
Tis constrained byany, so its type set comprises anythingr.Methodis of typestring, andstringisn't assignable to anything.
With map[string]any instead any is not used as a constraint, it is used as a static type, which is an alias of interface{} and all types are always assignable to the empty interface.
If you want to have a container with different runtime types, using any as a static type as in map[string]any is the only way. To restrict allowed types, use basic interfaces instead of type parameters.
See also the top-voted answer here: What are the benefits of replacing an interface argument with a type parameter?
