Home > Software design >  Expected slice but got interface
Expected slice but got interface

Time:11-07

I'm using sqlx package to make my database queries. I'm trying to create a global SELECT * for all my models in my database package

func FindAll(model interface{}, table string, db *sqlx.DB) error {
    err := db.Select(&model, "SELECT * FROM " table)
    if err != nil {
        return fmt.Errorf("FindAll: %v", err)
    }
    return nil
}

And I'm using it like this

albums := []Album{}
err := database.FindAll(albums, "album", a.DB)

But I got this error : expected slice but got interface

I don't know how can I manage the first model parameter to make it works for any models

CodePudding user response:

Inside FindAll(), the model parameter is of interface{} type. You pass a value of []Album to it. It already wraps a slice value.

db.Select() also expects an argument of interface type (the same interace{} type). And you have an interface value of exactly this type, just pass it as-is:

err := db.Select(model, "SELECT * FROM " table)

Although note that in order for db.Select() to be able to modify it, it must be a pointer, so model should wrap a pointer to a slice, not "just" a slice. So call FindAll() like this:

err := database.FindAll(&albums, "album", a.DB)

When you pass a value of concrete type when an interface type is needed, it will be wrapped in an interface value.

When you pass an interface value, if it is of the same interface type, it will be passed as-is. If it's a different interface type, the concrete value stored in it will be wrapped (re-wrapped) in an interface value of the expected interface type.

When you pass &model, you're passing a value of *interface{}, a pointer to an interface type. That's not an interface type, it's a concrete type, so this concrete type will be wrapped in an interface value when passed.

See related question: Golang interface{} type misunderstanding

  • Related