在带有结构键的地图上使用 maps.Copy 时出现 1.18 通用编译错误
go 1.18 generic compile error when use maps.Copy on map with struct key
我实现了一个基于泛型的 Set,一切正常,直到我使用 struct 作为 Set 元素而不是基类型。我遇到编译错误。
go 版本:go version go1.18 windows/amd64
以下代码在函数 AddSet
.
中编译失败
package main
import (
"fmt"
"golang.org/x/exp/maps"
)
type Key struct {
A, B int
}
func main() {
s := SetOf(
Key{1, 1},
Key{2, 2},
Key{3, 3},
)
s.AddSet(SetOf(
Key{3, 3},
Key{4, 4},
Key{5, 5},
))
fmt.Println(s)
}
type Set[T comparable] map[T]struct{}
func SetOf[T comparable](vs ...T) Set[T] {
s := Set[T]{}
for _, v := range vs {
s[v] = struct{}{}
}
return s
}
func (s Set[T]) AddSet(another Set[T]) {
maps.Copy(s, another)
}
当运行时:
> go run .\main.go
# command-line-arguments
.\main.go:19:10: cannot use &.autotmp_29 (type *struct { A int; B int }) as type *Key in argument to runtime.mapassign
<autogenerated>:1: cannot use &.autotmp_12 (type *struct { A int; B int }) as type *Key in argument to runtime.mapassign
- 如果
Key
只有1个字段,可以编译成功
- 如果我用
for v := range another { s[v]=struct{}{} }
,可以编译成功
我觉得很奇怪,有人可以解释一下吗?
看起来像this compiler error。它在 Go 1.19 中得到修复并向后移植到 Go 1.18.2。
如果您使用的是旧版本,我建议您放弃 maps
包并手动执行操作,正如您已经尝试过的那样。这只是一个简单的循环:
func (s Set[T]) AddSet(another Set[T]) {
for k := range another {
s[k] = struct{}{}
}
}
@icza 将命名映射类型显式转换为其基础类型的评论也有效:
maps.Copy(map[T]struct{}(s), another)
如果您使用需要多个映射类型参数(具有相同约束)的函数,如 maps.Equal
或 maps.EqualFunc
,您必须转换两个参数:
func (s Set[T]) Compare(another Set[T]) bool {
// signature is Equal[M1, M2 ~map[K]V, K, V comparable](m1 M1, m2 M2) bool
return maps.Equal(map[T]struct{}(s), map[T]struct{}(another))
}
似乎崩溃也是 reproduced 参数化映射类型用 len >= 2 的数组实例化。
我实现了一个基于泛型的 Set,一切正常,直到我使用 struct 作为 Set 元素而不是基类型。我遇到编译错误。
go 版本:go version go1.18 windows/amd64
以下代码在函数 AddSet
.
package main
import (
"fmt"
"golang.org/x/exp/maps"
)
type Key struct {
A, B int
}
func main() {
s := SetOf(
Key{1, 1},
Key{2, 2},
Key{3, 3},
)
s.AddSet(SetOf(
Key{3, 3},
Key{4, 4},
Key{5, 5},
))
fmt.Println(s)
}
type Set[T comparable] map[T]struct{}
func SetOf[T comparable](vs ...T) Set[T] {
s := Set[T]{}
for _, v := range vs {
s[v] = struct{}{}
}
return s
}
func (s Set[T]) AddSet(another Set[T]) {
maps.Copy(s, another)
}
当运行时:
> go run .\main.go
# command-line-arguments
.\main.go:19:10: cannot use &.autotmp_29 (type *struct { A int; B int }) as type *Key in argument to runtime.mapassign
<autogenerated>:1: cannot use &.autotmp_12 (type *struct { A int; B int }) as type *Key in argument to runtime.mapassign
- 如果
Key
只有1个字段,可以编译成功 - 如果我用
for v := range another { s[v]=struct{}{} }
,可以编译成功
我觉得很奇怪,有人可以解释一下吗?
看起来像this compiler error。它在 Go 1.19 中得到修复并向后移植到 Go 1.18.2。
如果您使用的是旧版本,我建议您放弃 maps
包并手动执行操作,正如您已经尝试过的那样。这只是一个简单的循环:
func (s Set[T]) AddSet(another Set[T]) {
for k := range another {
s[k] = struct{}{}
}
}
@icza 将命名映射类型显式转换为其基础类型的评论也有效:
maps.Copy(map[T]struct{}(s), another)
如果您使用需要多个映射类型参数(具有相同约束)的函数,如 maps.Equal
或 maps.EqualFunc
,您必须转换两个参数:
func (s Set[T]) Compare(another Set[T]) bool {
// signature is Equal[M1, M2 ~map[K]V, K, V comparable](m1 M1, m2 M2) bool
return maps.Equal(map[T]struct{}(s), map[T]struct{}(another))
}
似乎崩溃也是 reproduced 参数化映射类型用 len >= 2 的数组实例化。