• go:匿名函数与闭包


    一、匿名函数

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

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

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

        ----来自知乎回答: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赋值给d
    fmt.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 := 0
    	return func(cc int) int {
    		sum += cc
    		fmt.Println("aa=", aa, "bb=", bb, "	sum=", sum)
    		return sum
    	}
    }//编译错误,提示aa未定义

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

      更正后:

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

      调用1:

    func main() {
    	a := A()//定义变量a,并将函数A的返回值赋给a
    	b := 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
    */
    

      

      

      

      

      

  • 相关阅读:
    [转] 百万级数据查询优化
    vs生成失败不报错
    C# 编译器错误对应代码详细信息
    使用XSL 样式表无法查看XML 输入。请更正错误然后单击刷新按钮
    vs中release模式调试和错误:CA0503:无法显示额外的代码分析警告或错误
    sp_executesql的用法
    一个for循环根据条件可以递增或递减
    Lc.exe已退出 代码为1
    将所有输出窗口文本重定向到即时窗口
    两步解决《内部服务器错误:500》
  • 原文地址:https://www.cnblogs.com/xiaopipi/p/4900587.html
Copyright © 2020-2023  润新知