Golang:可变参数

4

当我编译以下程序时

func myPrint(v ...interface{}) {
        fmt.Println("Hello", v...)
}
func main() {
    myPrint("new", "world")
}

我遇到了编译错误。

too many arguments in call to fmt.Println

我认为v...会扩展到第2和第3个参数,而fmt.Println将看到三个项目的可变参数列表。 我认为这相当于

fmt.Println("Hello", "new", "world")

为什么它会出现错误?
2个回答

6
尝试这个。它会在可变参数前面添加“Hello”,然后使用println一次性打印所有参数。
package main

import "fmt"

func myPrint(v ...interface{}) {
    a := append([]interface{}{"Hello"}, v...)   // prepend "Hello" to variadics
    fmt.Println(a...)                           // println the whole lot
}
func main() {
    myPrint("new", "world")
}

2
谢谢,那个方法可行。我也用了同样的方法。但是我想知道为什么另一个方法不起作用。这是语言规范的预期行为还是编译器的异常行为? - Joseph Swaminathan

2
你在调用 fmt.Println() 时误用了可变参数的简写方式。实际上,你发送了两个参数:一个字符串和被展开的类型为 interface{} 的切片。函数调用将不会将它们连接成单一的切片。
这样的设计可以编译并运行,并得到你期望的结果:
func myPrint(v ...interface{}) {
    fmt.Print("Hello ")
    fmt.Println(v...)
}

func main() {
    myPrint("new", "world")
}

谢谢。所以,似乎扩展的 n 个元素的切片与传递 n 个参数不同。扩展的定义是什么?编译器为什么要将一个参数后面跟随的扩展视为不同于一个单独的扩展列表呢? - Joseph Swaminathan
根据Go规范,“我们在对Sprintln进行嵌套调用时,在v后面加上“...”来告诉编译器将v视为参数列表;否则,它只会将v作为单个切片参数传递。” 基于以上声明,正确的行为应该是将其视为参数列表而不是单个切片参数。我甚至尝试了以下代码,但它并不起作用:func myPrint(v ...interface{}) { fmt.Println(interface{}("Hello"), v...) } - Joseph Swaminathan
问题不在编译器,而在解析器。函数调用 fmt.Println("Hello", v...) 会使用逗号将其解析为两个参数,然后发送到编译器。如果没有这个过程,就需要一套复杂的类型检查和验证来决定前面的参数是否属于列表。如果有一个函数 fmt.Println(s string, v...interface{}) 和另一个 fmt.Println(v...interface{}),编译器如何能够将该调用匹配到函数上呢? - SnoProblem
这就是为什么两个扩展切片不能用于相同的可变参数列表,例如 fmt.Println(v..., v...) - SnoProblem
非常感谢您的解释。所以这是 Golang 的多态性在起作用。我现在明白了。 - Joseph Swaminathan
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接