How can I build varidics of type interface in Go?

huangapple go评论83阅读模式
英文:

How can I build varidics of type interface in Go?

问题

我正在动态构建MySQL查询(由于MySQL的IN子句),所以我需要将参数列表作为sql.Query函数的参数传递。你有任何关于如何实现这一点的想法吗?我真的不太理解可变参数类型是如何工作的,或者如何“生成”它。如果我传递一个切片,SQL会抱怨只有一个参数,而不是len(in clause params),因此我只能假设该函数将切片视为参数,而不是参数列表(可变参数)。

我的查询/代码:

var carsa []string
q := `SELECT field1,field2 FROM cooltable WHERE nicecars IN(?` + strings.Repeat(",?", len(ha.cars)-1) + ")"
hs := strings.Join(carsa, "','")
hs = "'" + hs + "'"

rows, err := cx.Query(q, country, hs)

SQL查询:

func (db *DB) Query(query string, args ...interface{}) (*Rows, error) {

编辑:我尝试运行的实际代码失败,并显示错误sql: converting Exec argument #0's type: unsupported type []interface {}, a slice

package main

import (
    "database/sql"
    "fmt"
    _ "github.com/go-sql-driver/mysql"
)

func main() {

    argsS := []string{"apple", "greph", "3rd"}

    db, err := sql.Open("mysql", dbUser+":"+dbPass+"@tcp("+dbHost+":3306)/"+dbName)
    if err != nil {
        return
    }
    query := `SELECT id,label FROM fruits WHERE country=? AND stack IN(?` + strings.Repeat(",?", len(args)-1) + ")"

    args := make([]interface{}, len(ha))
    args["country"] = interface{}("France")

    for i, v := range query {
        args[i] = interface{}(v)
    }

    rows, err := db.Query(q, args...)
    if err != nil {
        return
    }
    var id, label string

    for rows.Next() {
        if err = rows.Scan(&id, label); err != nil {
            fmt.Printf("%v", err)
        }
    }
}
英文:

I'm building mysql query dynamically ( due the mysql IN clause) so I need to pass a list of arguments as the sql.Query function requires. Any idea how can do that ? I don't really understand how the variadic type works or how I can 'generate' it. If I pass a slice the sql complains that there is only one parameter instead of len(in clause params) thus I can only assume that the function sees the slice as a parameter instead a list ( variadic ) of parameters.

My query / code

var carsa []string
q := `SELECT field1,field2 FROM cooltable WHERE nicecars IN(?` + strings.Repeat(",?", len(ha.cars)-1) + ")"
hs := strings.Join(carsa, "','")
hs = "'" + hs + "'"

rows, err := cx.Query(q, country, hs)

sql Query

func (db *DB) Query(query string, args ...interface{}) (*Rows, error) {

Edit: The actual code I'm trying to run fails with error sql: converting Exec argument #0's type: unsupported type []interface {}, a slice

package main

import (
	"database/sql"
	"fmt"
	_ "github.com/go-sql-driver/mysql"
)

func main() {

	argsS := []string{"apple", "greph", "3rd"}

	db, err := sql.Open("mysql", dbUser+":"+dbPass+"@tcp("+dbHost+":3306)/"+dbName)
	if err != nil {
		return
	}
	query := `SELECT id,label FROM fruits WHERE country=? AND stack IN(?` + strings.Repeat(",?", len(args)-1) + ")"

	args := make([]interface{}, len(ha))
	args["country"] = interface{}("France")

	for i, v := range query {
		args[i] = interface{}(v)
	}

	rows, err := db.Query(q, args...)
	if err != nil {
		return
	}
	var id, label string

	for rows.Next() {
		if err = rows.Scan(&id, label); err != nil {
			fmt.Printf("%v", err)
		}
	}
}

答案1

得分: 5

使用给定的函数,您可以将其与变量参数列表一起调用,如下所示:

var query string
var args []interface{}
// 初始化变量
cx.Query(query, args...)

这等效于将args切片中的每个元素作为单独的参数传递给Query函数,详细信息请参阅语言规范。请注意,切片的类型需要与可变参数函数的定义匹配(在这种情况下是interface{}的切片)。

还要注意,切片需要表示整个可变参数列表。例如,使用cx.Query(q, country, hs...)这样的调用是错误的。在这种情况下,您需要构建一个包含要传递的所有参数的切片。


根据问题的更新,要将固定参数与变量参数组合起来,您的代码应该类似于以下示例:

stacks := []string{"apple", "greph", "3rd"}

query := `SELECT id,label FROM fruits WHERE country=? AND stack IN(?` + strings.Repeat(",?", len(stacks)-1) + ")"

args := make([]interface{}, len(stacks)+1)
args[0] = "France"
for i := range stacks {
    args[i+1] = stacks[i]
}

rows, err := cx.Query(query, args...)
英文:

With the given function, you can call it with a variable argument list as:

var query string
var args []interface{}
// initialise variables
cx.Query(query, args...)

This is equivalent to calling Query with each of the elements in the args slice passed as separate arguments, as described in the language specification. Note also that the type of the slice needs to match the variadic function definition (so in this case a slice of interface{}.

Note also that the slice needs to represent the entire variadic argument list. So it would be an error to call cx.Query(q, country, hs...), for example. In cases like that, you will need to construct a slice that holds all the arguments you want to pass.


Following on from the question's update, to combine the fixed arguments with your variable ones you want your code to look something like this:

stacks := []string{"apple", "greph", "3rd"}

query := `SELECT id,label FROM fruits WHERE country=? AND stack IN(?` + strings.Repeat(",?", len(stacks)-1) + ")"

args := make([]interface{}, len(stacks)+1)
args[0] = "France"
for i := range stacks {
    args[i+1] = stacks[i]
}

rows, err := cx.Query(query, args...)

huangapple
  • 本文由 发表于 2014年7月22日 11:10:46
  • 转载请务必保留本文链接:https://go.coder-hub.com/24878264.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定