Eugene Lisitsky
Eugene Lisitsky

Reputation: 12845

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.

Upvotes: 6

Views: 7082

Answers (1)

icza
icza

Reputation: 417702

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

Upvotes: 9

Related Questions