如何使用反射在Golang中调用Scan variadic函数?[英] How to call the Scan variadic function in Golang using reflection?

本文是小编为大家收集整理的关于如何使用反射在Golang中调用Scan variadic函数?的处理/解决方法,可以参考本文帮助大家快速定位并解决问题,中文翻译不准确的可切换到English标签页查看源文。

问题描述

我希望调用 Rows.Scan() 函数使用反射.但是它需要可变数量的指针,但是我是 Golang 的新手,并且没有很多源示例.我需要使用反射,因为我计划用 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>]

推荐答案

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

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

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 {

            var v interface{}

            val := values[i]

            b, ok := val.([]byte)

            if (ok) {
                v = string(b)
            } else {
                v = val
            }

            fmt.Println(col, v)
        }
    }
}

本文地址:https://www.itbaoku.cn/post/597513.html

问题描述

I'm looking to call the Rows.Scan() function using reflection. However it takes a variable number of pointers, but I'm new to Golang and there are not a lot of source examples. I need to use reflection because I plan on filling a slice with the values from a Query call. So basically using rows.Columns() to get the length of the row and then make() a slice of []interface{} to fill with the data points that would normally be filled using the pointers passed to the Scan() function.

Basically something like this code:

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

Anyone have an example of calling a variadic function that takes pointers using reflection that I can take a look at?

Edit: Sample code that doesn't appear to do what I'm after.

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

}

The results:

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

推荐答案

Here's the solution that I've arrived at. It doesn't get the Types before traversing the data, and so doesn't know before hand the type of each value before pulling the values out through Scan(), but the point really is to not have to know the types before hand.

The trick was to create 2 slices, one for the values, and one that holds pointers in parallel to the values slice. Then once the pointers are used to fill data, the values array is actually filled with the data, which can then be used to populate other data structures.

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 {

            var v interface{}

            val := values[i]

            b, ok := val.([]byte)

            if (ok) {
                v = string(b)
            } else {
                v = val
            }

            fmt.Println(col, v)
        }
    }
}