编程后端开发者

描述 Go 语言中 variadic 函数(可变参数函数)的实现。如何正确声明、调用这些函数,以及在传递切片时可能会遇到哪些问题?

用 Hintsage AI 助手通过面试

答案

Go 语言中的 variadic 函数允许接收一个类型可变数量的参数,得益于 ... 语法。例如:

func sum(nums ...int) int { total := 0 for _, num := range nums { total += num } return total }

可以使用任意数量的参数来调用此函数:

result := sum(1, 2, 3, 4) // 10

或者使用 ... 语法传递切片:

numbers := []int{1,2,3} result := sum(numbers...) // 6

细节:

  • 在函数中,variadic 参数被视为切片 ([]T)。这意味着可以传入已准备好的切片。
  • 这样的参数必须始终是函数参数列表中的最后一个。
  • 如果不使用 ... 传递切片,函数会期望一个普通的参数类型 []T 而不是 variadic。

有陷阱的问题

以下代码的结果是多少,为什么?

func printInts(nums ...int) { fmt.Printf("%#v ", nums) } ints := []int{1, 2, 3} printInts(ints)

许多人错误地认为这段代码会编译成功,但实际上会引发编译错误:

错误: 不能不使用 ... 将切片传递给 variadic 参数。

正确:

printInts(ints...) // OK

由于不了解主题细节造成的真实错误示例


故事

在一个大型项目中,日志记录函数被描述为 func Log(msgs ...string)。在传递已准备好的字符串切片时,直接调用 Log(strings),导致日志输出不正确或运行时 panic。原因是缺少 ...,因此函数将其视为一个类型为 []string 的参数,而不是单独的字符串。


故事

在一个工具函数中,需要处理参数,其中有一个切片,并希望在内部向其添加更多元素。原以为 ... 会创建切片的副本,而不是传递引用——但在函数内部修改切片,这意外影响了调用方,特别是当原切片是可重用的缓冲区时。


故事

开发人员使用 variadic 参数实现了聚合函数,但同事错误使用了通过类型转换的调用语法:sum(interface{}([]int)),这导致运行时隐性错误,而正确的做法是明确使用 sum(slice...)。对细节的不了解导致在大规模重构中出现难以察觉的 bug。