I implemented a Set based on generic, and everything ok until i use struct as Set element instead of base type. I got an compliation error.
go version: go version go1.18 windows/amd64
Below code is failed to complie in function 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)
}
when run it:
> 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
- if
Key
only has 1 field, it can be compiled successful. - if i use
for v := range another { s[v]=struct{}{} }
, it can be compiled successful.
i think it's strange, can someone explain please?
CodePudding user response:
It looks like this compiler error. Likely it will be fixed in Go 1.19 and backported to Go 1.18.1.
For now I'd recommend simply forgoing the maps
package and doing things by hand, as you already tried. It's just a simple loop:
func (s Set[T]) AddSet(another Set[T]) {
for k := range another {
s[k] = struct{}{}
}
}
@icza's comment of explicitly converting the named map type to its underlying type also works:
maps.Copy(map[T]struct{}(s), another)
In case you use functions that expect more than one map type parameter (with the same constraints), as maps.Equal
or maps.EqualFunc
, you have to convert both arguments:
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))
}
It seems the crash is reproduced also with parametrized map types instantiated with arrays with len >= 2.