golang 函数二 (匿名函数和闭包)

前端之家收集整理的这篇文章主要介绍了golang 函数二 (匿名函数和闭包)前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

匿名函数就是没有定义函数名称函数。我们可以在函数内部定义匿名函数,也叫函数嵌套。

匿名函数可以直接被调用,也可以赋值给变量、作为参数或返回值。比如:

  1. funcmain(){
  2. func(sstring){//直接被调用
  3. println(s)
  4. }("hellogopher!!!")
  5. /*
  6. func(sstring){//未被调用
  7. println(s)
  8. }
  9. */
  10. }
  11.  
  12. funcmain(){
  13. hi:=func(sstring){//赋值给变量
  14. println(s)
  15. }
  16. hi("hellogopher!!!")
  17. }
  18.  
  19.  
  20. functest(ffunc(string)){
  21. f("hellogopher!!!")
  22. }
  23. funcmain(){
  24. hi:=func(sstring){
  25. println(s)
  26. }
  27. test(hi)//作为参数
  28. }
  29.  
  30. functest()func(string){
  31. hi:=func(sstring){//作为返回值
  32. println(s)
  33. }
  34. returnhi
  35. }
  36.  
  37. funcmain(){
  38. f:=test()
  39. f("hellogopher!!!")
  40. }

普通函数和匿名函数都可以作为结构体的字段,比如:

  1. {
  2. typecalcstruct{
  3. mulfunc(x,yint)int
  4. }
  5. x:=calc{
  6. mul:func(x,yint)int{
  7. return(x*y)
  8. },}
  9. println(x.mul(2,3))
  10. }

也可以经channel(通道)传递,比如:

  1. {
  2. c:=make(chanfunc(int,int)int,2)
  3. c<-func(x,yint)int{returnx+y}
  4. println((<-c)(2,3))
  5. }

闭包(closure)

闭包是指在上下文中引用了自由变量(未绑定到特定对象)的代码块(函数),或者说是代码块(函数)与和引用环境的组合体。比如:

  1. funcintSeq()func()int{
  2. i:=0
  3. println(&i)
  4. returnfunc()int{
  5. i+=1
  6. println(&i,i)
  7. returni
  8. }
  9. }
  10.  
  11. funcmain(){
  12. nextInt:=intSeq()
  13. fmt.Println(nextInt())
  14. fmt.Println(nextInt())
  15. fmt.Println(nextInt())
  16.  
  17. newInt:=intSeq()
  18. fmt.Println(newInt())
  19. }
  20. 输出
  21. 0xc42000a320
  22. 0xc42000a3201
  23. 1
  24. 0xc42000a3202
  25. 2
  26. 0xc42000a3203
  27. 3
  28. 0xc42007a010
  29. 0xc42007a0101
  30. 1

当nextInt函数返回后,通过输出指针,我们可以看出函数在main运行时,依然引用的是原环境变量指针,这种现象称作闭包。所以说,闭包是函数和引用环境变量的组合体。

因为闭包是通过指针引用环境变量,那么就会导致该变量的生命周期

变长,甚至被分配到堆内存。如果多个匿名函数引用同一个环境变量,会让事情变得更加复杂,比如:

  1. functest()[]func(){
  2. vars[]func()
  3. fori:=0;i<3;i++{
  4. s=append(s,func(){
  5. println(&i,i)
  6. })
  7. }
  8. returns
  9. }
  10. funcmain(){
  11. funcSlice:=test()
  12. for_,f:=rangefuncSlice{
  13. f()
  14. }
  15. }
  16. 输出
  17. 0xc42000a3203
  18. 0xc42000a3203
  19. 0xc42000a3203

解决方法就是每次用不同的环境变量或参数赋值,比如修改后的test函数

  1. functest()[]func(){
  2. vars[]func()
  3. fori:=0;i<3;i++{
  4. x:=i
  5. s=append(s,func(){
  6. println(&x,x)
  7. })
  8. }
  9. returns
  10. }

闭包在不用传递参数的情况下就可以读取和修改环境变量,当然我们是要为这种遍历付出代价的,所以日常开发中,在高并发服务

的场景下建议慎用,除非你明确你的需求必须这样做。

猜你在找的Go相关文章