閉包的思想

思考一個(gè)問題:
如何能夠在運(yùn)行的時(shí)候生成或者改變一個(gè)函數(shù)?
比如在一個(gè)函數(shù)外部修改一個(gè)變量就能改變這個(gè)函數(shù)的行為?

于是一個(gè)稱之為閉包的東西出現(xiàn)了。
閉包:函數(shù)和引用的外部變量一起構(gòu)成一個(gè)閉包。

?注意:如果沒有上述目的,不要引用函數(shù)外部的變量。把它作為參數(shù)傳入你的函數(shù)。否則你很有可能因此引入意想不到的bug。

如何實(shí)現(xiàn)閉包?
下面是golang的實(shí)現(xiàn)

以下引自https://hitzhangjie.github.io/jekyll/update/2018/05/19/golang-function-closure%E5%AE%9E%E7%8E%B0%E6%9C%BA%E5%88%B6.html

  1. 假如閉包定義后立即被調(diào)用 因?yàn)橹粫皇褂靡淮?,所以?yīng)該力圖避免閉包對象的內(nèi)存分配操作,那怎么優(yōu)化一下呢,以下面的示例代碼為例。
func(a int) {
    println(byval)
    byref++
}(42)

上面的閉包將被轉(zhuǎn)換為簡單函數(shù)調(diào)用的形式:

func(byval int, &byref *int, a int) {
    println(byval)
    (*&byref)++
}(byval, &byref, 42)

注意看函數(shù)原型的變化,原來閉包里面捕獲的變量都被轉(zhuǎn)換成了通過函數(shù)參數(shù)來供值:

因?yàn)閜rintln操作不涉及對byval變量的修改操作,所以是按值捕獲;
而byref++涉及到對捕獲變量的修改,所以是按引用捕獲,對于按引用捕獲的變量會進(jìn)行特殊處理,golang編譯器會在編譯時(shí)將按引用捕獲的變量名byref轉(zhuǎn)換成“&byref”,同時(shí)將其類型轉(zhuǎn)換成pointer類型,捕獲變量對應(yīng)的寫操作也會轉(zhuǎn)換為通過pointer來操作。
2) 假如閉包定以后并不是立即調(diào)用 閉包定義后不是立即使用,而是后續(xù)調(diào)用,這種情況下同一個(gè)閉包可能調(diào)用多次,這種情況下就需要?jiǎng)?chuàng)建閉包對象,如何實(shí)現(xiàn)呢?

如果變量是按值捕獲,并且該變量占用存儲空間小于2*sizeof(int),那么就通過在函數(shù)體內(nèi)創(chuàng)建局部變量的形式來shadow捕獲的變量,相比于通過引用捕獲,這么做的好處應(yīng)該是考慮到減少引用數(shù)量、減少逃逸分析相關(guān)的計(jì)算。
如果變量是按引用捕獲,或者按值捕獲但是捕獲的變量占用存儲空間較大(拷貝到本地做局部變量代價(jià)太大),這種情況下就將捕獲的變量var轉(zhuǎn)換成pointer類型的“&var”,并在函數(shù)prologue階段將其初始化為捕獲變量的值。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容