一尘不染

如何使用反射调用扫描可变参数函数

go

我想使用反射调用Rows.Scan()函数。但是,它需要使用可变数量的指针,但是没有很多源示例。我需要使用反射,因为我计划用Query调用中的值填充一个切片。因此,基本上使用rows.Columns()来获取行的长度,然后make()使用来切片[]interface{}以填充通常使用传递给Scan()函数的指针填充的数据点。

基本上像这样的代码:

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

有人举过一个调用可变参数函数的例子,该函数使用我可以查看的反射来获取指针?

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

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)
    }

}

结果:

[<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>]

阅读 210

收藏
2020-07-02

共1个答案

一尘不染

这是我到达的解决方案。它在遍历数据之前没有获得Types,因此在将值拉出之前不事先知道每个值的类型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)
        }
    }
}
2020-07-02