匿名函数就是没有定义函数名称的函数。我们可以在函数内部定义匿名函数,也叫函数嵌套。
匿名函数可以直接被调用,也可以赋值给变量、作为参数或返回值。比如:
- funcmain(){
- func(sstring){//直接被调用
- println(s)
- }("hellogopher!!!")
- /*
- func(sstring){//未被调用
- println(s)
- }
- */
- }
- funcmain(){
- hi:=func(sstring){//赋值给变量
- println(s)
- }
- hi("hellogopher!!!")
- }
- functest(ffunc(string)){
- f("hellogopher!!!")
- }
- funcmain(){
- hi:=func(sstring){
- println(s)
- }
- test(hi)//作为参数
- }
- functest()func(string){
- hi:=func(sstring){//作为返回值
- println(s)
- }
- returnhi
- }
- funcmain(){
- f:=test()
- f("hellogopher!!!")
- }
- {
- typecalcstruct{
- mulfunc(x,yint)int
- }
- x:=calc{
- mul:func(x,yint)int{
- return(x*y)
- },}
- println(x.mul(2,3))
- }
也可以经channel(通道)传递,比如:
- {
- c:=make(chanfunc(int,int)int,2)
- c<-func(x,yint)int{returnx+y}
- println((<-c)(2,3))
- }
闭包(closure)
闭包是指在上下文中引用了自由变量(未绑定到特定对象)的代码块(函数),或者说是代码块(函数)与和引用环境的组合体。比如:
- funcintSeq()func()int{
- i:=0
- println(&i)
- returnfunc()int{
- i+=1
- println(&i,i)
- returni
- }
- }
- funcmain(){
- nextInt:=intSeq()
- fmt.Println(nextInt())
- fmt.Println(nextInt())
- fmt.Println(nextInt())
- newInt:=intSeq()
- fmt.Println(newInt())
- }
- 输出:
- 0xc42000a320
- 0xc42000a3201
- 1
- 0xc42000a3202
- 2
- 0xc42000a3203
- 3
- 0xc42007a010
- 0xc42007a0101
- 1
当nextInt函数返回后,通过输出指针,我们可以看出函数在main运行时,依然引用的是原环境变量指针,这种现象称作闭包。所以说,闭包是函数和引用环境变量的组合体。
因为闭包是通过指针引用环境变量,那么就会导致该变量的生命周期
变长,甚至被分配到堆内存。如果多个匿名函数引用同一个环境变量,会让事情变得更加复杂,比如:
- functest()[]func(){
- vars[]func()
- fori:=0;i<3;i++{
- s=append(s,func(){
- println(&i,i)
- })
- }
- returns
- }
- funcmain(){
- funcSlice:=test()
- for_,f:=rangefuncSlice{
- f()
- }
- }
- 输出:
- 0xc42000a3203
- 0xc42000a3203
- 0xc42000a3203
解决方法就是每次用不同的环境变量或参数赋值,比如修改后的test函数:
- functest()[]func(){
- vars[]func()
- fori:=0;i<3;i++{
- x:=i
- s=append(s,func(){
- println(&x,x)
- })
- }
- returns
- }
闭包在不用传递参数的情况下就可以读取和修改环境变量,当然我们是要为这种遍历付出代价的,所以日常开发中,在高并发服务
的场景下建议慎用,除非你明确你的需求必须这样做。