go:匿名函数与闭包

来源:转载

一、匿名函数

定义:没有函数名的函数。

作用:在go语言中目前了解的作用就是用于构成闭包。

*注:由于js不存在块级作用域,故匿名函数常用来包含代码以不污染全局命名空间,运行后销毁环境。

----来自知乎回答:http://www.zhihu.com/question/34649602

使用方法及其原理请参考:http://www.cnblogs.com/chenxianbin89/archive/2010/01/28/1658392.html

使用举例

(1)

a := func() {fmt.Println(1)}a() //输出:1

(2)带参数

b := func(arg int) {fmt.Println(arg)}b(2) //输出:2(func(arg int) {fmt.Println(arg)})(3) //输出:3

(3)带返回值

c := func() int {fmt.Println(4)return 5}d := c() //打印输出4,并将5赋值给dfmt.Println(d)

二、闭包(closure)

闭包的理解参考:http://www.cnblogs.com/mzwr1982/archive/2012/05/20/2509295.html

闭包的用途参考:http://blog.csdn.net/sunlylorn/article/details/6534610

和 http://www.cnblogs.com/rainman/archive/2009/05/04/1448899.html

简单来说:

因为把返回的函数赋给了一个变量,虽然函数在执行完一瞬间会销毁其执行环境,

但是如果有闭包的话,闭包会保存外部函数的活动对象(变量),所以如果不把对闭包的引用消除掉,

闭包会一直存在内存中,垃圾收集器不会销毁闭包占用的内存。

----来自知乎回答http://www.zhihu.com/question/34649602

使用举例

(1)

//函数A是一个不带参数,返回值是一个匿名函数,且该函数//带有一个int类型参数,返回值为一个int类型func A() func(aa int) int {sum := 0return func(cc int) int {sum += ccfmt.Println("aa=", aa, "bb=", bb, "sum=", sum)return sum}}//编译错误,提示aa未定义

实际上func(aa int) int只是函数A的返回值,在这里给参数取名无任何作用,反而会影响代码阅读,直接用func(int) int 即可。

更正后:

func A() func(int) int {sum := 0return func(bb int) int {sum += bbfmt.Println("bb=", bb, "/tsum=", sum)return sum}}

调用1:

func main() {a := A()//定义变量a,并将函数A的返回值赋给ab := a(4)fmt.Println(b)}/*** 输出: ** bb= 4 sum= 4** 4*/

调用2:

func main() {a := A()a(0)a(1)a(5)}/*** 输出:** bb= 0 sum= 0** bb= 1 sum= 1** bb= 5 sum= 6*/

以上调用通过闭包实现了sum的累加

调用3:

func main() {a := A()c := A()a(0)a(5)c(10)c(20)}/*** 输出:** bb= 0 sum= 0** bb= 5 sum= 5** bb= 10 sum= 10** bb= 20 sum= 30 */

可以看出,上例中调用了两次函数A,构成了两个闭包,这两个闭包维护的变量sum不是同一个变量。

(2)

func B() []func() {b := make([]func(), 3, 3)for i := 0; i < 3; i++ {b[i] = func() {fmt.Println(i)}}return b}func main() {c := B()c[0]()c[1]()c[2]()}/*** 输出:** 3** 3** 3*/

闭包通过引用的方式使用外部函数的变量。

上例中只调用了一次函数B,构成一个闭包,i 在外部函数B中定义,所以闭包维护该变量 i ,c[0]、c[1]、c[2]中的 i 都是闭包中 i 的引用。

因此执行c:=B()后,i 的值已经变为3,故再调用c[0]()时的输出是3而不是0。

可作如下修改:

func B() []func() {b := make([]func(), 3, 3)for i := 0; i < 3; i++ {b[i] = (func(j int) func() {return func() {fmt.Println(j)}})(i)}return b}func main() {c := B()c[0]()c[1]()c[2]()}/*** 输出:** 0** 1** 2*/

以上修改可能没有什么实际意义,此处仅为说明问题使用。

在使用defer的时候可能出现类似问题,需要注意:

for j := 0; j < 2; j++ {defer (func() {fmt.Println(j)})()}/*** 输出: ** 2 ** 2*/



分享给朋友:
您可能感兴趣的文章:
随机阅读: