关于go:将字符串切片传递给variadic空接口参数


Pass string slice to variadic empty interface parameter

我使用的包gosqlite具有一个方法,该方法具有一个可变参数,其类型为空接口。

1
func (s *Stmt) Exec(args ...interface{}) os.Error

如果显式传递单个参数,我可以调用此fine:

1
2
statement := blah()
error := statement.Exec("hello", 3.0, true) // works fine

但是,由于variadic参数对应于我的SQL语句的selectin运算符中的占位符,因此这些占位符的数量在编译时不知道,但在运行时根据用户所做的操作动态更改。例如,如果用户输入了四个值,那么我最终得到的SQL类似于以下内容:

1
SELECT * FROM sky WHERE name IN (?,?,?,?)

因此,我当然想用一段字符串调用Exec方法:

1
2
3
var values []string = getValuesFromUser()
statement := createStatementWithSufficientNumberOfPlaceholders(len(values))
_ := statement.Exec(values...) // compiler doesn't like this

这不编译。我可以通过创建一个空接口切片并复制引用来解决这个问题:

1
2
3
values2 := make([]interface{}, len(values))
for index, value := range values { values2[index] = value }
_ := statement.Exec(values2...) // compiler happy but I'm not

这个很好用,但感觉有点笨重。我想知道是否有一些技巧可以将values直接传递给这个函数,或者如果没有这个技巧,可以用一种更简洁的方法将字符串切片转换为空接口片?

非常感谢。


无法将[]string直接传递给...interface{}参数。这样做需要一个线性时间拷贝(使用n+1分配!)如果语言对你隐瞒了这一点,那将是一个巨大的隐藏成本。通常,将一个切片传递给变量参数只是将该切片传递给函数。

至于其他方法,您可以通过编写一个函数使它更清晰,该函数接受一个[]string并返回相应的[]interface{}。当然,对于您想要进行的每个[]T->[]interface{}转换,您必须重新编写它,但是它的函数很短,所有的更改都是签名。您可以使用具有固有运行时成本的反射来使函数"通用",例如:

1
2
3
valuesVal := reflect.ValueOf(values)
...
for i := range values2 { values2[i] = valuesVal.Index(i).Interface() }


我没有答案。我不认为有这样一个,因为即使是内置的和可变的copy和append都有相同(或兼容的具体)的元素类型"blockhead",但我有两个明显的建议:

  • 不从getValuesFromUser()返回[]string(即通行证仍为未加修改的[]interface{})
  • 在另一个类型上,使用func将[]string转换为[]interface{}来结束对statement.Exec()的调用。
  • 小精灵

    同样,第三,明显的音符扩展了type statementExec(args ...string)

    另外,我自己也没有做任何基准测试,但我不认为这种转换是非常昂贵的,因为界面感觉像是一种引用类型,编译器可能在幕后做了一些肮脏的诡计……不过,也许不是,我也会很高兴知道一个实际的解决方案。