1. 函数参数和返回值的写法
如果有多个参数是同一个类型,可以简略写:
func testReturnFunc(v1,v2 int)(int,int) {x1 := 2 * v1x2 := 3 * v2return x1,x2
}
Go 还支持命名返回值的方式。命名返回值作为结果形参(result parameters)被初始化为相应类型的零值,当需要返回的时候,我们只需要一条简单的不带参数的 return 语句 :
func testReturnFunc1(v int)(x1,x2 int) {x1 = 2 * vx2 = 3 * vreturn
}
函数返回的是 x1 和 x2 这两个值,如果 x1,x2 没有在函数中被赋值,那么会返回这两个参数的默认值。
2. 如何改变函数外部的变量
使用我们前面讲到的指针,得到一个外部参数的指针,将该指针作为参数传入函数中,这样对该指针赋值操作就相当于修改了该指针指向内存地址对应变量的值:
func multiply(a,b int,reply *int) {*reply = a *b
}func main() {num := 0reply := &nummultiply(3,5,reply)fmt.Println("return num :",*reply,num)
}输出:
return num : 15 15
3. 将函数作为参数
函数可以作为其它函数的参数进行传递,然后在其它函数内调用执行,一般称之为回调 。
package mainimport "fmt"func main() {callback(4,add)
}func add(a,b int) {fmt.Print(a+b)
}func callback(c int, f func(int, int)) {f(c,c)
}输出:
8
我理解这种回调的方式,使用场景在于多个方法之间形成调用链,下一个方法依赖上一个方法的某些值的时候,相当于 callback 是第一个方法,add 是第二个方法,add 方法需要依赖 callback 方法中的某些中间值。
4. 匿名函数---闭包
Go 语言支持匿名函数,即函数可以像普通变量一样被传递或使用。
i2 := func(x, y int) int { return x + y }(1,2)
如上,定义了一个匿名函数,包含两个参数 x,y。返回 x+y 的结果。后面的 () 表示参数,参数是 x=1,y=2。
当然你也可以先定义匿名函数,不适用,等你需要使用的时候,像调用函数一样传参数就可以:
i2 := func(x, y int) int { return x + y }
i3 := i2(x, y)
两种方式的区别就在于 (x,y) 参数放在哪里。
在 Go 语言中匿名函数和闭包是一个概念:
闭包是可以包含自由(未绑定到特定对象)变量的代码块,这些变量不在这个代码块内或者 任何全局上下文中定义,而是在定义代码块的环境中定义。要执行的代码块(由于自由变量包含 在代码块中,所以这些自由变量以及它们引用的对象没有被释放)为自由变量提供绑定的计算环 境(作用域)。
闭包的价值 闭包的价值在于可以作为函数对象或者匿名函数,对于类型系统而言,这意味着不仅要表示 数据还要表示代码。支持闭包的多数语言都将函数作为第一级对象,就是说这些函数可以存储到 变量中作为参数传递给其他函数,最重要的是能够被函数动态创建和返回。
”
Go 语言中的闭包同样也会引用到函数外的变量。闭包的实现确保只要闭包还被使用,那么被闭包引用的变量会一直存在。
我们再看一个复杂一点的例子:
func aa() {a := 5b := func()(func()){c := 10return func() {fmt.Printf("a,c: %d,%d n",a,c)a *= 3}}()b()println(a)
}
输出:
a,c: 5,10
15
解释一下:
匿名函数的返回值是一个匿名函数,return 返回的是一个匿名函数,注意没有加()
,所以是用 return 接收。
然后在最外层是加了()
的。所以将匿名函数的值给了 b。注意了此时的 b 其实是一个函数。所以下面在使用的时候是b()
。你可以尝试将匿名函数的最外层的 ()
去掉,然后看一下b()
打印的值是什么,在试一下b()()
打印的值是什么。
另外,a 在匿名函数内是可以引用的,但是你如果在匿名函数外引用 c,你会发现找不到。并且在闭包内改变了 a 的值也是会作用到 a 真实的内存地址中的。