0

I am experimenting with go generics, and I have encountered this issue. Why is Schedule not matching any?

Code

func demo(m Model[any]) Model[any] {
    return m
}

type Model[M any] interface {
    FindOne(db *gorm.DB, conds ...any) (m M)
}

type DbOperations[M any] struct{}

func (d DbOperations[M]) FindOne(db *gorm.DB, conds ...any) (m M) {
    res := db.First(&m, conds)
    if res.Error != nil {
        return m
    }
    return m
}


// the program does not compile because of this function
func a() {
    m := DbOperations[Schedule]{}
    get(m) // <= error occurs here
}

Error message

../models/operations.go:103:6: cannot use m (variable of type DbOperations[Schedule]) as type Model[any] in argument to get:
    DbOperations[Schedule] does not implement Model[any] (wrong type for FindOne method)
        have FindOne(db *gorm.DB, conds ...any) (m Schedule)
        want FindOne(db *gorm.DB, conds ...any) any
Chuma Umenze
  • 933
  • 12
  • 18

1 Answers1

1

The go language usually requires you to be explicit about the types you're using, and generally does not automatically cast variables for you. So this doesn't work because Model[any] (aka Model[interface{}]) and Model[Schedule] are not the same types. (more details below)

What you could do instead, is also make get a generic func:

func get[T any](m Model[T]) Model[T] {
    return m
}

and then indicate what the type is when you call the func:

func a() {
    m := DbOperations[Schedule]{}
    get[Schedule](m)
}

Details

Model[any] != Model[SomeType] for the same reason why you can't pass a string slice to a func that takes an any slice parameter:

A []interface{} slice has a different memory layout than a []Schedule slice. Similarly, a Model[T] is laid out in memory differently than a Model[any]. Go expects you to do the work of converting them. (summarizing the official explanation and SO answers here)

xgord
  • 4,606
  • 6
  • 30
  • 51