Go语言入门系列前面的文章:算法
在Go语言入门系列(二)之基础语法总结这篇文章中已经介绍过了Go语言的函数的基本使用,包括声明、参数、返回值。本文再详细介绍一下函数的其余使用。编程
Go语言的函数除了支持0个或多个参数,还支持不定数量的参数,即变参。声明方式为:数组
func foo(变参名 ...参数类型) 函数类型 { //函数体 }
下面是一个具体的函数,它接收不定数量的int
参数,并返回和:数据结构
package main import "fmt" func add(arg ...int) int { //变参函数 var sum int for _, value := range arg { sum += value } return sum } func main() { sum := add(1, 2, 3, 4) fmt.Println(sum) //10 }
arg ...int
代表add
函数接收不定数量的参数,且只能是int
类型的。arg
是咱们给该变参取的名字,它其实是一个切片,因此在add
函数中可使用range
遍历变量arg
。app
当咱们调用一个有参函数时,确定会向该函数中传入参数:数据结构和算法
package main import "fmt" //传入一个值,打印它 func printX(x int) { fmt.Println(x) } func main() { var a int = 5 printX(a) //向函数中传入参数:变量a }
这里有一个问题:咱们真的是把变量a
传给了printX
函数吗?咱们用两个例子来讲明问题。函数
package main import "fmt" func plusOne(x int) int { x = x + 1 fmt.Println("执行加一") return x } func main() { a := 5 fmt.Println("a =", a) //应该为5 实际为5 b := plusOne(a) fmt.Println("a =", a) //应该为6 实际为5 fmt.Println("b =", b) //应该为6 实际为6 }
plusOne
函数的做用是把传进来的参数加一,并返回结果。spa
a=5
传进plusOne
函数,执行了x = x + 1
语句,那么执行事后a
的值应该为6,但实际为5。指针
变量b
接收了函数的返回值,因此为6,这没问题。code
这证实了,咱们的a
变量根本就没传进函数中,那么实际传的是什么?实际传的是a
变量的一份拷贝。
因此,咱们向Go语言中的函数传入一个值,实际上传的是该值的拷贝,而非该值自己。
那若是咱们确实要把上例中的变量a
传入plusOne
函数中呢?那此时就不该该传值了,而是应该传入指针。代码改进以下:
package main import "fmt" func plusOne(x *int) int { //参数是指针变量 *x = *x + 1 fmt.Println("执行加一") return *x } func main() { a := 5 fmt.Println("a =", a) //应该为5 实际为5 b := plusOne(&a) //传入地址 fmt.Println("a =", a) //应该为6 实际为6 fmt.Println("b =", b) //应该为6 实际为6 }
a=5
传进plusOne
函数,执行了x = x + 1
语句,执行事后a
的值实际为6。
这就证实,变量a
确实被传进plusOne
函数并被修改了。由于咱们传进去的是一个指针,即变量的地址,有了地址咱们能够直接操做变量。
若是你对指针的使用不熟悉,这里的代码可能会有点难理解,下面逐行解释:
func plusOne(x *int) int {
声明x
是一个int
类型的指针参数,只接受int
类型变量的地址 。
*x = *x + 1
使用*
操做符根据x
中存的地址,获取到对应的值,而后加一。
return *x
使用*
操做符根据x
中存的地址,获取到对应的值,而后返回。
b := plusOne(&a)
plusOne
函数只接受int
类型变量的地址,因此使用&
操做符获取a
变量的地址,而后才传入。
下面我再举一个经典的例子:写一个函数,可以交换两个变量的值。
若是你不知道什么是传值和传指针,那可能会写成这样:
package main import "fmt" func swap(x, y int) { tmp := x x = y y = tmp fmt.Println("函数中:x =", x, ", y =", y) } func main() { x, y := 2, 8 fmt.Println("交换前:x =", x, ", y =", y) swap(x, y) fmt.Println("交换后:x =", x, ", y =", y) }
运行结果:
交换前:x = 2 , y = 8 函数中:x = 8 , y = 2 交换后:x = 2 , y = 8
只在函数中完成了交换,出了函数又变回原样了。
想要完成交换,就必须传入指针,而非值拷贝:
package main import "fmt" func swap(x, y *int) { tmp := *x *x = *y *y = tmp fmt.Println("函数中:x =", *x, ", y =", *y) } func main() { x, y := 2, 8 fmt.Println("交换前:x =", x, ", y =", y) swap(&x, &y) fmt.Println("交换后:x =", x, ", y =", y) }
运行结果:
交换前:x = 2 , y = 8 函数中:x = 8 , y = 2 交换后:x = 8 , y = 2
传入指针可以真正交换两个变量的值。
传入指针的好处:
在Go语言中,函数也能够做为值来传递。下面是一个例子:
package main import "fmt" type calculate func(int, int) int // 声明了一个函数类型 func sum(x, y int) int { return x + y } func product(x, y int) int { return x * y } func choose(a, b int, f calculate) int { //函数做为参数 return f(a, b) } func main(){ diff := func(x, y int) int { //函数做为值赋给diff return x - y } fmt.Println(choose(2, 3, sum)) //5 fmt.Println(choose(4, 5, product)) //20 fmt.Println(choose(6, 7, diff)) //-1 fmt.Println(diff(9, 8)) //1 }
函数做为值或者参数确定要有对应的类型,类型是:func(参数类型)返回值类型
。好比func(int,int) int
可使用type
关键字给func(int,int) int
起个别名叫calculate
,方便使用。
choose
函数中声明了一个类型为calculate
的函数参数f
,而咱们又编写了calculate
类型的函数sum
和product
,因此能够向choose
函数中传入这两个函数。
咱们给变量diff
赋了一个函数,因此可以使用diff(9, 8)
,或者将其做为参数传入choose
函数。
我是「 行小观」,于千万人中的一个普通人。阴差阳错地走上了编程这条路,既然走上了这条路,那么我会尽量远地走下去。我会在公众号『行人观学』中持续更新「Java」、「Go」、「数据结构和算法」、「计算机基础」等相关文章。
欢迎关注,咱们一块儿踏上行程。
本文章属于系列文章「Go语言入门系列」。
若有错误,还请指正。