這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。
1 形式含義
聽 聽 所謂閉包就是一個函數“捕獲”了和它在同一作用於的其他常量和變數。
聽 聽 從形式上看,在Golang中,所有的匿名函數都是閉包。閉包的建立方式和普通函數幾乎一致,只有一個關鍵區別:閉包沒有名字。
聽 聽 我們來看兩個例子
addPng聽:=聽func(name聽string)聽string聽{聽return聽name聽+聽".png"聽}addJpg聽:=聽func(name聽string)聽string聽{聽return聽name聽+聽".jpg"聽}filename聽:=聽"abc"fmt.Println(addPng(filename),聽addJpg(filename))
聽 聽 結果如下
//聽工廠函數,傳回值也是一個函數funcaddSuffix(suffix聽string)聽func(string)聽string聽{聽聽聽聽return聽func(name聽string)聽string聽{聽聽聽聽聽聽聽聽if聽!strings.HasSuffix(name,聽suffix)聽{聽聽聽聽聽聽聽聽聽聽聽聽name聽=聽name聽+聽suffix聽聽聽聽聽聽聽聽}聽聽聽聽聽聽聽聽return聽name聽聽聽聽}}聽…聽func聽main()聽{聽聽聽聽聽聽…聽聽聽聽addZip聽:=聽addSuffix(".zip")聽聽聽聽addTgz聽:=聽addSuffix(".tar.gz")聽聽聽聽fmt.Println(addZip(filename),addTgz(filename))}
2 實質含義
聽 聽 僅僅從形式上將閉包簡單理解為匿名函數是不夠的,還需要理解閉包實質上的含義。
聽 聽 實質上看,閉包是由函數及其相關引用環境組合而成的實體(即:閉包=函數+引用環境)。閉包在運行時可以有多個執行個體,不同的引用環境和相同的函數組合可以產生不同的執行個體。由閉包的實質含義,我們可以推論:閉包擷取捕獲變數相當於引用傳遞,而非值傳遞;對於閉包函數捕獲的常量和變數,無論閉包何時何處被調用,閉包都可以使用這些常量和變數,而不用關心它們表面上的範圍。
聽 聽 我們用一個例子來進行驗證。
funcaddNumber(x聽int)聽func(int)聽{聽聽聽聽fmt.Printf("x:聽%d,聽addr聽of聽x:%p\n",聽x,聽&x)聽聽聽聽return聽func(y聽int)聽{聽聽聽聽聽聽聽聽k聽:=聽x聽+聽y聽聽聽聽聽聽聽聽x聽=聽k聽聽聽聽聽聽聽聽y聽=聽k聽聽聽聽聽聽聽聽fmt.Printf("x:聽%d,聽addr聽of聽x:%p\n",聽x,聽&x)聽聽聽聽聽聽聽聽fmt.Printf("y:聽%d,聽addr聽of聽y:%p\n",聽y,聽&y)聽聽聽聽}}聽func聽main()聽{聽聽聽聽addNum聽:=聽addNumber(5)聽聽聽聽addNum(1)聽聽聽聽addNum(1)聽聽聽聽addNum(1)聽聽聽聽聽fmt.Println("---------------------")聽聽聽聽聽addNum1聽:=聽addNumber(5)聽聽聽聽addNum1(1)聽聽聽聽addNum1(1)聽聽聽聽addNum1(1)}
聽 聽 運行結果
聽 聽 首先強調一點,x是閉包中被捕獲的變數,y只是閉包內部的局部變數,而非被捕獲的變數。因此,對於每一次引用,x的地址都是固定的,是同一個引用變數;y的地址則是變化的。另外,閉包被引用了兩次,由此產生了兩個閉包執行個體,即addNum := addNumber(5)和addNum1 :=addNumber(5)是兩個不同執行個體,其中引用的兩個x變數也來自兩個不同的執行個體。
本文出自 “說話的白菜” 部落格,謝絕轉載!