4

I want to use Scan() in package sql, but the number of columns, and hence the number of arguments, will change at runtime. This is the signature of Scan():

func (rs *Rows) Scan(dest ...interface{}) error 

According to the documentation, *interface{} is one of the types accepted by Scan(). So I want to create a slice of []*interface{} and that expand as arguments.

This is what I thought would work:

func query(database *sql.DB) { rows, _ := database.Query("select * from testTable") for rows.Next() { data := make([]*interface{}, 2) err := rows.Scan(data...) // Compilation error fmt.Printf("%v%v\n", *data[0], *data[1]) if err != nil { fmt.Println(err.Error()) } } } 

Compilation fails with cannot use data (type []*interface {}) as type []interface {} in argument to rows.Scan. I thought that data... would expand to &data[0], &data[1], but apparently not. I don't understand the error message. *interface{} is compatible with interface{}, so why can't I expand the slice of pointers to interface types?

This works:

func query(database *sql.DB) { rows, _ := database.Query("select * from testTable") for rows.Next() { data := make([]*interface{}, 2) err := rows.Scan(&data[0], &data[1]) // Only changed this line fmt.Printf("%v%v\n", *data[0], *data[1]) // Outputs "[48][116 101 120 116]" if err != nil { fmt.Println(err.Error()) } } } 

I can't use this however, because the number of columns is unknown at compile time. How can I write this code so that I can pass a variable number of *interface{} to rows.Scan()?

3
  • 2
    Why do you want []*interface{} instead of []interface{}? Commented Dec 7, 2018 at 8:12
  • I just thought that []*interface{} gets me closest to the answer. I will edit my question to add this detail. Commented Dec 7, 2018 at 16:43
  • 1
    Pointers to interfaces are almost never the right approach. Commented Dec 7, 2018 at 20:24

2 Answers 2

6

First, you must not use []*interface{} slice of pointers to interface rather than []interface{} where the interfaces are pointers. []*interface{} is different from []interface{}. Just create a slice of interfaces where each element is a pointer to a concrete type.

Here is a snippet how you would do this.

var x int var s string data := []interface{}{&x, &s} rows.Scan(data...) 

Note on the use of the ... spread operator.

Here are some related questions that will explain a bit more:

golang: slice of struct != slice of interface it implements?

Cannot convert []string to []interface {}

Sign up to request clarification or add additional context in comments.

Comments

1

If you really want to pass a []*interface{} (perhaps you don't know the concrete types of the output) you must first wrap each *interface{} in a interface{}:

values := make([]interface{}, columnsCount) for i := range values { values[i] = new(interface{}) } 

Individual values passed into a ...interface{} parameter are automatically wrapped in a interface{}, but just like []int... won't satisfy ...interface{}, neither will []*interface{}....

1 Comment

This works great if you don't know anything about the query. Thanks!

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.