如何使用反射在Golang中调用Scan variadic函数?

luc*_*iet 29 database reflection go

我想用反射来调用Rows.Scan()函数.然而,它需要可变数量的指针,但我是Golang的新手,并没有很多源代码示例.我需要使用反射,因为我计划使用Query调用中的值填充切片.所以基本上使用rows.Columns()获得该行的长度,然后make()切片[]interface{}来填充数据点通常会使用传递到指针填充Scan()功能.

基本上像这样的代码:

col := rows.Columns()
vals := make([]interface{}, len(cols))
rows.Scan(&vals)
Run Code Online (Sandbox Code Playgroud)

任何人都有一个调用可变参数函数的例子,它使用我可以看一下的反射来获取指针?

编辑:示例代码似乎没有做我想要的.

package main

import (
    _ "github.com/lib/pq"
    "database/sql"
    "fmt"
)


func main() {

    db, _ := sql.Open(
        "postgres",
        "user=postgres dbname=Go_Testing password=ssap sslmode=disable")

    rows, _ := db.Query("SELECT * FROM _users;")

    cols, _ := rows.Columns()

    for rows.Next() {

        data := make([]interface{}, len(cols))

        rows.Scan(data...)

        fmt.Println(data)
    }

}
Run Code Online (Sandbox Code Playgroud)

结果:

[<nil> <nil> <nil> <nil> <nil>]
[<nil> <nil> <nil> <nil> <nil>]
[<nil> <nil> <nil> <nil> <nil>]
[<nil> <nil> <nil> <nil> <nil>]
[<nil> <nil> <nil> <nil> <nil>]
[<nil> <nil> <nil> <nil> <nil>]
Run Code Online (Sandbox Code Playgroud)

luc*_*iet 50

这是我到达的解决方案.它在遍历数据之前没有得到类型,因此在拉出值之前不知道每个值的类型Scan(),但关键是真的不必事先了解类型.

诀窍是创建2个切片,一个用于值,另一个用于保持与值切片平行的指针.然后,一旦指针用于填充数据,则值数组实际上填充了数据,然后可以使用这些数据来填充其他数据结构.

package main

import (
    "fmt"
    _ "github.com/lib/pq"
    "database/sql"
)

func main() {
    db, _ := sql.Open(
        "postgres",
        "user=postgres dbname=go_testing password=pass sslmode=disable")

    rows, _ := db.Query("SELECT * FROM _user;")

    columns, _ := rows.Columns()
    count := len(columns)
    values := make([]interface{}, count)
    valuePtrs := make([]interface{}, count)

    for rows.Next() {
        for i := range columns {
            valuePtrs[i] = &values[i]
        }

        rows.Scan(valuePtrs...)

        for i, col := range columns {
            val := values[i]

            b, ok := val.([]byte)
            var v interface{}
            if (ok) {
                v = string(b)
            } else {
                v = val
            }

            fmt.Println(col, v)
        }
    }
}
Run Code Online (Sandbox Code Playgroud)


小智 5

要清醒:您还可以分配界面而不是制作切片

以下代码效果很好:

var sql = "select * from table"
rows, err := db.Query(sql)
columns, err = rows.Columns()
colNum := len(columns)

var values = make([]interface{}, colNum)
for i, _ := range values {
    var ii interface{}
    values[i] = &ii
}

for rows.Next() {
    err := rows.Scan(values...)
    for i, colName := range columns {
        var raw_value = *(values[i].(*interface{}))
        var raw_type = reflect.TypeOf(raw_value)

        fmt.Println(colName,raw_type,raw_value)
    }
}
Run Code Online (Sandbox Code Playgroud)