golang中的可变参数可以让函数接受任意数量的参数,这为函数的设计和调用带来了极大的灵活性。本文将从golang函数参数默认值、golang参数默认值、golang函数参数、golang可选参数、golang main参数、golang变长参数、golang参数传递、golang切片作为参数这几个方面来详细阐述golang可变参数。
一、golang函数参数默认值
golang中的函数参数默认值是实现不了的,这主要是为了避免在调用函数时由于参数顺序错乱而导致问题。golang只支持在函数声明时为每个参数指定类型但不指定初始值,也就是说golang中不存在如下形式的函数声明:
func example(a int, b string = "default value") { // do something }
换句话说,在golang中我们必须在调用函数时为每个参数都指定一个值,否则编译器会报错。
二、golang参数默认值
虽然golang中没有函数参数默认值这一特性,但是我们可以通过函数重载来达到类似的效果。具体来说,当我们定义一个函数时,可以定义多个具有不同参数个数以及不同参数类型的函数版本,这些函数版本中参数较少的版本可以给不传递对应参数的函数调用提供默认值。下面是一个例子:
func example(a int, b string) { // do something } func example(a int) { example(a, "default value") }
在上面的例子中,当我们调用example(1)时,函数example(a int)就会被调用,并且此时函数的参数b会被赋值为"default value"。
三、golang函数参数
golang中的函数参数传递是按值传递,也就是说函数接收的参数是传入参数的值的拷贝,而不是传入参数的引用。因此,在函数内部修改函数参数的值,不会影响传入函数的参数的值,如下面的例子所示:
func example(a int) { a = 2 } func main() { b := 1 example(b) fmt.PrintLn(b) // 输出1 }
在上面的例子中,尽管函数example内部将参数a的值修改为2,但是这并不影响main函数中传入example函数的参数b的值,因为golang中的函数参数传递是按值传递。
四、golang可选参数
golang中没有内置的可选参数的概念,但是我们可以通过函数重载或者结构体来实现类似的效果。下面分别介绍这两种实现方式。
通过函数重载实现:
func example(a []int) { example(a, 1) } func example(a []int, b int) { // do something } func main() { example([]int{1, 2, 3}) // 调用example(a []int, b int) }
在上面的例子中,函数example(a []int)会调用函数example(a []int, b int),并且给参数b传递默认值1。
通过结构体实现可选参数:
type ExampleParams struct { A []int B int } func example(params ExampleParams) { // do something } func main() { example(ExampleParams{A: []int{1, 2, 3}, B: 1}) example(ExampleParams{A: []int{1, 2, 3}}) }
在上面的例子中,我们通过结构体ExampleParams来实现可选参数,当我们调用example函数时,可以选择传入ExampleParams结构体,并对其中的字段进行赋值,也可以只传入部分字段,未传入的字段就会使用默认值。
五、golang main参数
在golang中,main函数有一个默认的参数类型是[]string,也就是一个字符串切片。在我们通过终端运行一个程序时,可以通过在命令行后面添加多个参数,这些参数就会被作为字符切片传入main函数中。下面是一个例子:
func main() { fmt.Println(os.Args) }
在上面的例子中,我们使用os包获取命令行参数,并将其输出。例如我们运行以下命令行:
go run main.go a b c
那么输出结果就是:
[./main a b c]
六、golang变长参数
golang中的变长参数类型用...标识,在函数定义时可以为最后一个参数指定变长参数类型。在函数内部,变长参数可以视为一个slice类型的变量,我们可以对其进行遍历和操作。下面是一个例子:
func example(args ...int) { for _, arg := range args { fmt.Println(arg) } } func main() { example(1, 2, 3) }
在上面的例子中,我们定义了一个函数example,它的最后一个参数类型是...int,这表示它可以接收任意数量的int类型参数。在函数内部,我们直接将变长参数args当做一个slice类型变量来处理,并遍历其中的每一个元素并输出。
七、golang参数传递
在golang中,函数参数传递有两种方式,分别是按值传递和按引用传递。前文已经提到,golang中的函数参数传递是按值传递,但是我们可以使用指针来模拟按引用传递。下面是一个例子:
func example(a *int) { *a = 2 } func main() { b := 1 example(&b) fmt.Println(b) // 输出2 }
在上面的例子中,我们使用指针来传递参数b的引用,从而实现了类似于按引用传递的效果。
八、golang切片作为参数
在golang中,切片类型是一种引用类型,因此当我们将切片作为函数参数传递时,函数接收到的是该切片的引用,也就是说在函数内部修改切片的元素的值,也会影响到函数外部传递的切片的值。下面是一个例子:
func example(a []int) { a[0] = 2 } func main() { b := []int{1, 2, 3} example(b) fmt.Println(b) // 输出[2, 2, 3] }
在上面的例子中,我们将切片b作为参数传递给了函数example,函数内部修改了切片的第一个元素的值,这也导致了函数外部切片b的第一个元素的值被修改。