我想知道为什么不能在go中执行以下操作:
func main() {
stuff := []string{"baz", "bla"}
foo("bar", stuff...)
}
func foo(s ...string) {
fmt.Println(s)
}
根据我的理解,切片......“爆炸”切片,以便它可以用于多参数函数调用。所以上面的例子实际上应该扩展到foo("bar", "baz", "bla")
。
foo(stuff...)
按预期工作,这里没什么惊喜,但在上面的例子中,编译器抱怨参数太多。
这是一个理想的限制吗?我来自一个红宝石背景,其中foo("bar", *stuff)
非常好(至少在我的书中,同样的事情),这就是为什么这让我感到惊讶。
答案 0 :(得分:9)
可变参数的值可以通过使用现有切片枚举元素或来指定 ,该切片由其名称后跟...
指定。
您希望混合使用Go语言规范(Passing arguments to ...
parameters)不允许的两种可能方式。
如果使用第一个表单(枚举元素):
传递的值[作为variadic参数]是一个新的
[]T
类型的切片,带有一个新的底层数组,其连续的元素是实际的参数。
如果使用后者(传递现有切片后跟...
)没有创建新切片,则传递的切片将按原样使用。传递的切片只能用于指定一个的值 - final - variadic参数。尝试传递单个元素和切片与您的函数的签名(在本例中为参数列表)不匹配,您将收到错误:
too many arguments in call to foo
Go中没有涉及实际的“爆炸”,该术语仅用于其他语言,以帮助可视化传递的数组或切片不是可变参数的元素但将是variadic参数本身的值。
混合2将需要分配新切片,因为显然不能使用现有切片。
答案 1 :(得分:5)
关于此的规范在" Passing arguments to ...
parameters":
如果
f
为变量型,其最终参数p
的类型为...T
,那么f
中p
的类型等同于[]T
的类型}}。
如果在f
没有实际参数的情况下调用p
,则传递给p
的值为nil
。
否则,传递的值是类型为[]T
的新切片,其中包含一个新的基础数组,其连续元素是实际参数,所有这些参数都必须可分配给T
。
在你的情况下,哪些东西......有效:
如果最终参数可分配给切片类型
[]T
,则如果参数后跟...T
,则可以将其作为...
参数的值保持不变。在这种情况下,不会创建新切片。
但是"bar", stuff...
与上面指定的任何一种情况都不匹配。
T, []T
与f([]T)
不匹配。
答案 2 :(得分:1)
让它发挥作用的丑陋方法是将其变成一种新的变量。
foo(append([]string{"bar"}, stuff...)...)
答案 3 :(得分:1)
我在准备参数以提供给外部命令时遇到了这种情况。 如果可能,只需构建一个单参数切片,那么您就不必担心 在调用函数时将标量与切片组合:
package main
import "os/exec"
func main() {
stuff := []string{"bar"}
stuff = append(stuff, "baz", "bla")
exec.Command("name", stuff...).Run()
}