Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

map[gorm.DB]struct{}{} gives invalid map key type gorm.DB

I'd like to create a "set" of gorm types used in my application. So I'd like to define a map with my types gorm.DB as keys and empty structs{} as flags:

var (
    autoMigrations map[gorm.DB]struct{}
)

But compiler doesn't allow me do this with error: invalid map key type gorm.DB. I can fool it using pointers to gorm.DBs like:

map[*gorm.DB]struct{}

But it's not a solution, because I need to make it unique and if my map gets filled like db.AutoMigrate(&Chat{}) I can get lots of similar object with different addresses.

Another solution is to make a slice of gorm.DB:

autoMigrations []gorm.DB

But I have to filter elements on addition manually, which seems insane a little bit.

like image 829
Eugene Lisitsky Avatar asked Nov 08 '17 09:11

Eugene Lisitsky


1 Answers

You can only use types as keys in a map that are comparable. Spec: Map types:

The comparison operators == and != must be fully defined for operands of the key type; thus the key type must not be a function, map, or slice.

gorm.DB is a struct, and struct values are only comparable if all their fields are comparable:

Struct values are comparable if all their fields are comparable. Two struct values are equal if their corresponding non-blank fields are equal.

But gorm.DB has e.g. a DB.values field which is a map type, and maps are not comparble, and thus gorm.DB values are not comparable either, and so you can't use it as map keys.

If you want to create a set of types, you should use reflect.Type as the map keys, which you can acquire using reflect.TypeOf() from a value of that type.

A little trick, if you want a reflect.Type without having to create a value of the type in question, you can start from a pointer value of that type (which may be nil), and use Type.Elem() to get the reflect.Type descriptor of the pointed type.

For example, to get the reflect.Type descriptor of a struct type Point struct{ X, Y int } without actually creating / having a Point:

type Point struct{ X, Y int }
tpoint := reflect.TypeOf((*Point)(nil)).Elem()
fmt.Println(tpoint)

Which prints main.Point. Try it on the Go Playground.

See related questions:

How can I prevent a type being used as a map key?

Why can't Go slice be used as keys in Go maps pretty much the same way arrays can be used as keys?

Set of structs in Go

like image 110
icza Avatar answered Nov 12 '22 01:11

icza