前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >GO 匿名函数和闭包

GO 匿名函数和闭包

作者头像
孤烟
发布2020-09-27 11:03:16
4730
发布2020-09-27 11:03:16
举报

匿名函数:顾名思义就是没有名字的函数。很多语言都有如:java,js,php等,其中js最钟情。匿名函数最大的用途是来模拟块级作用域,避免数据污染的。

今天主要讲一下Golang语言的匿名函数和闭包。

匿名函数

示例:

1、

package main

import (
   "fmt"
)
func main() {
   f:=func(){
      fmt.Println("hello world")
   }
   f()//hello world
   fmt.Printf("%T\n", f) //打印 func()
}

2、带参数

package main

import (
   "fmt"
)
func main() {
   f:=func(args string){
      fmt.Println(args)
   }
   f("hello world")//hello world
   //或
   (func(args string){
        fmt.Println(args)
    })("hello world")//hello world
    //或
    func(args string) {
        fmt.Println(args)
    }("hello world") //hello world
}

3、带返回值

package main

import "fmt"

func main() {
   f:=func()string{
      return "hello world"
   }
   a:=f()
   fmt.Println(a)//hello world
}

4、多个匿名函数

package main

import "fmt"

func main() {
   f1,f2:=F(1,2)
   fmt.Println(f1(4))//6
   fmt.Println(f2())//6
}
func F(x, y int)(func(int)int,func()int) {
   f1 := func(z int) int {
      return (x + y) * z / 2
   }

   f2 := func() int {
      return 2 * (x + y)
   }
   return f1,f2
}

闭包(closure)

闭包:说白了就是函数的嵌套,内层的函数可以使用外层函数的所有变量,即使外层函数已经执行完毕。

示例:

1、

package main

import "fmt"

func main() {
    a := Fun()
    b:=a("hello ")
    c:=a("hello ")
    fmt.Println(b)//worldhello 
    fmt.Println(c)//worldhello hello 
}
func Fun() func(string) string {
    a := "world"
    return func(args string) string {
        a += args
        return  a
    }
}

2、

package main

import "fmt"

func main() {
   a := Fun()
   d := Fun()
   b:=a("hello ")
   c:=a("hello ")
   e:=d("hello ")
   f:=d("hello ")
   fmt.Println(b)//worldhello
   fmt.Println(c)//worldhello hello
   fmt.Println(e)//worldhello
   fmt.Println(f)//worldhello hello
}
func Fun() func(string) string {
   a := "world"
   return func(args string) string {
      a += args
      return  a
   }
}

注意两次调用F(),维护的不是同一个a变量。

3、

package main

import "fmt"

func main() {
   a := F()
   a[0]()//0xc00004c080 3
   a[1]()//0xc00004c080 3
   a[2]()//0xc00004c080 3
}
func F() []func() {
   b := make([]func(), 3, 3)
   for i := 0; i < 3; i++ {
      b[i] = func() {
         fmt.Println(&i,i)
      }
   }
   return b
}

闭包通过引用的方式使用外部函数的变量。例中只调用了一次函数F,构成一个闭包,i 在外部函数B中定义,所以闭包维护该变量 i ,a[0]、a[1]、a[2]中的 i 都是闭包中 i 的引用。因此执行,i 的值已经变为3,故再调用a[0]()时的输出是3而不是0。

4、如何避免上面的BUG ,用下面的方法,注意和上面示例对比。

package main

import "fmt"

func main() {
    a := F()
    a[0]() //0xc00000a0a8 0
    a[1]() //0xc00000a0c0 1
    a[2]() //0xc00000a0c8 2
}
func F() []func() {
    b := make([]func(), 3, 3)
    for i := 0; i < 3; i++ {
        b[i] = (func(j int) func() {
            return func() {
                fmt.Println(&j, j)
            }
        })(i)
    }
    return b
}
或者
package main

import "fmt"

func main() {
    a := F()
    a[0]() //0xc00004c080 0
    a[1]() //0xc00004c088 1
    a[2]() //0xc00004c090 2
}
func F() []func() {
    b := make([]func(), 3, 3)
    for i := 0; i < 3; i++ {
        j := i
        b[i] = func() {
            fmt.Println(&j, j)
        }
    }
    return b
}

每次 操作仅将匿名函数放入到数组中,但并未执行,并且引用的变量都是 i,随着 i 的改变匿名函数中的 i 也在改变,所以当执行这些函数时,他们读取的都是环境变量 i 最后一次的值。解决的方法就是每次复制变量 i 然后传到匿名函数中,让闭包的环境变量不相同。

5、

package main

import "fmt"

func main() {
   fmt.Println(F())//2
}
func F() (r int) {
   defer func() {
      r++
   }()
   return 1
}

输出结果为2,即先执行r=1 ,再执行r++。

6、递归函数

还有一种情况就是必须用都闭包,就是递归函数。

package main

import "fmt"

func F(i int) int {
   if i <= 1 {
      return 1
   }
   return i * F(i-1)
}

func main() {
   var i int = 3
   fmt.Println(i, F(i))// 3 6
}

7、斐波那契数列(Fibonacci)

这个数列从第3项开始,每一项都等于前两项之和。

package main

import "fmt"

func fibonaci(i int) int {
    if i == 0 {
        return 0
    }
    if i == 1 {
        return 1
    }
    return fibonaci(i-1) + fibonaci(i-2)
}

func main() {
    var i int
    for i = 0; i < 10; i++ {
        fmt.Printf("%d\n", fibonaci(i))
    }
}

小结:

匿名函数和闭包其实是一回事儿,匿名函数就是闭包。匿名函数给编程带来灵活性的同时也容易产生bug,在使用过程当中要多注意函数的参数,及可接受的参数的问题。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 匿名函数
  • 闭包(closure)
  • 小结:
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档