這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。
一、匿名函數
定義:沒有函數名的函數。
作用:在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*/