在带有结构键的地图上使用 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

我觉得很奇怪,有人可以解释一下吗?

看起来像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.Equalmaps.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 的数组实例化。