英文:
How to set multiple types for generic values in Go correctly?
问题
我想在Golang中为哈希映射的值设置多个类型。我实现了Golang泛型any
,并编写了一个返回map[string]any
的函数。
然而,当我运行代码后,它返回了以下错误信息:
$ cannot use r.Method (variable of type string) as type T in map literal
在Go中,为哈希映射的值设置多个类型的正确方法是什么?
以下是我的代码:
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,
}
// 仅用于测试
p = map[string]T{
"method": r.Method, // << 这里出错了
}
return p
}
func main() {
p := SetRequestProperty(true)
}
[编辑]
尽管如此,这似乎是有效的...我不知道为什么。
package main
type RequestProperty struct {
Method string
Params []any
Id int
}
// 删除 [T any],map[string]T
// 将其改为 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,
}
// 仅用于测试
p = map[string]any{
"method": r.Method,
}
return p
}
func main() {
p := SetRequestProperty(true)
}
T
不应该只是类型any
的别名吗?我是否理解错了什么?
英文:
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?
答案1
得分: 2
> T 应该只是一个别名,指向 any 类型吗?
不,不应该。
T
是一个类型参数,而不是 any
。它只是受到 any
的约束。
更一般地说:类型参数并不等同于它的约束。
每次泛型函数被实例化时,T
都会被赋予一个具体的类型参数,该参数满足其约束条件。在函数体内部,map[string]T
就变成了一个从 string
到具体 T
类型的映射。
p := SetRequestProperty[int](true)
// 使得 body 看起来像:`var p map[string]int`
// 字面量 `map[string]int{"method": r.Method}` 显然是无法工作的
因此,在编译时,编译器会拒绝对 T
进行不与 T
类型集中的所有类型兼容的赋值。代码 map[string]T{"method": r.Method}
无法编译,因为:
T
受到any
的约束,所以它的类型集包括任何类型r.Method
的类型是string
,而string
无法赋值给任何类型。
<hr>
相反,如果使用 map[string]any
,any
并不是作为约束使用,而是作为静态类型,它是 interface{}
的别名,所有类型都可以赋值给空接口。
如果你想要拥有具有不同运行时类型的容器,使用 any
作为静态类型,如 map[string]any
,是唯一的方法。如果要限制允许的类型,可以使用基本接口而不是类型参数。
此外,还可以参考这里的最高票答案:https://stackoverflow.com/questions/71887083/what-are-the-benefits-of-replacing-an-interface-argument-with-a-type-parameter
英文:
> 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:
T
is constrained byany
, so its type set comprises anythingr.Method
is of typestring
, andstring
isn't assignable to anything.
<hr>
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: https://stackoverflow.com/questions/71887083/what-are-the-benefits-of-replacing-an-interface-argument-with-a-type-parameter
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论