爱上开源之golang入门至实战第四章函数(Func)(五)

4.4.5 变长参数

爱上开源之golang入门至实战第四章函数(Func)(五)_golang

 

变长参数传递的函数在很多语言里都是支持的,javascript里就有这样的函数, java在1.5以后也开始支持, 同样在go语言里也支持这样非常方便的变长参数的函数。 比如,我们最常用到的fmt.Println(), 见print.go源文件

// Println formats using the default formats for its operands and writes to standard output.
// Spaces are always added between operands and a newline is appended.
// It returns the number of bytes written and any write error encountered.
func Println(a ...any) (n int, err error) {
return Fprintln(os.Stdout, a...)
}

如上段源代码,Println函数就是变长参数的函数, ...any,表示数据类型为any的变参数;

下面我们示例一段变长参数的函数的例子

func Average(n ...int) float64 {
if len(n) == 0 {
return 0
}

sum := 0.0

for _, v := range n {
sum += float64(v)
}

return sum / float64(len(n)*1.0)
}
fmt.Printf("Average()=%v \n", Average())
fmt.Printf("Average(1)=%v \n", Average(1))
fmt.Printf("Average(1, 6)=%v \n", Average(1, 6))
fmt.Printf("Average(1, 2, 3, 4, 5)=%v \n", Average(1, 2, 3, 4, 5))
n := append(make([]int, 0), 2, 4, 6, 8, 10, 12)
fmt.Printf("Average(%v)=%v \n", n, Average(n...))

==== OUTPUT ====
Average()=0
Average(1)=1
Average(1, 6)=3.5
Average(1, 2, 3, 4, 5)=3
Average([2 4 6 8 10 12])=7

变长函数的最后一个参数是采用 ...type 的形式,那么这个函数就可以处理一个变长的参数,这个长度可以为 0,这样的函数称为变参函数。如上个例子,我们就定义了一个Average的变长参数的函数,Average函数参数定义为...int,表示处理一个int类型的变长参数,函数的实现,是变量所有的参数,然后累加计算平均值。 再来看看函数的调用。

Average(), 参数为0个参数

Average(1), 参数为1个参数

Average(1,6), 参数为2个参数

Average(1, 2, 3, 4, 5), 参数为5个参数

Average(n...), 参数为6个参数

注意最后一个调用参数的方式, Average(n...) n是一个数组或者是切片,可以通过...的方式,把一个数组或者切片转换为变长的参数进行传递, 这个方式在很多源代码里都有类似的调用。

在使用变长函数定义时要注意

  1. 一个变长参数的函数定义里,只能有一个变长的参数定义
  2. 一个变长参数的函数定义里,只能是最后一个参数定义能定义为变长的参数
func Says(name string, greets ...string) {
word := strings.Join(greets, " ")

fmt.Printf("%s: %s\n", name, word)
}
func TestReturnFunc2(t *testing.T) {
Says("Ginghan", "Welcome to", "Golang", "Java", "Python")

words := append(make([]string, 0), "like", "Golang", "Java", "Python", "C#", "Php", "C++", "Js")
Says("程序员紫龙", words...)
}

==== OUTPUT ====
Ginghan: Welcome to Golang Java Python
程序员紫龙: like Golang Java Python C# Php C++ Js

在上面的例子里,定义了Says变长参数的函数; 只能最后一个参数可以定义为变长的参数,如greets ...string;

words := append(make([]string, 0), "like", "Golang", "Java", "Python", "C#", "Php", "C++", "Js")

这里的代码,也是一个变长参数的函数的使用例子, golang里内置的append函数也是一个变长参数的函数, 参考builtin.go代码

// The append built-in function appends elements to the end of a slice. If
// it has sufficient capacity, the destination is resliced to accommodate the
// new elements. If it does not, a new underlying array will be allocated.
// Append returns the updated slice. It is therefore necessary to store the
// result of append, often in the variable holding the slice itself:
// slice = append(slice, elem1, elem2)
// slice = append(slice, anotherSlice...)
// As a special case, it is legal to append a string to a byte slice, like this:
// slice = append([]byte("hello "), "world"...)
func append(slice []Type, elems ...Type) []Type

这个append是处理切片非常常见的函数, 大家一定要熟记这个函数的用法。

变长的方式,只能作为变长参数,不能作为返回值。

func Says(name string, greets ...string) ...string {
word := strings.Join(greets, " ")

fmt.Printf("%s: %s\n", name, word)
}

==== Complie Error ====
.\build_test.go:546:43: can only use ... with final parameter in list

编译失败!!!

爱上开源之golang入门至实战第四章函数(Func)(五)_java_02

爱上开源之golang入门至实战第四章函数(Func)(五)_变长参数_03