Go匿名函數(shù)

GO語(yǔ)言的匿名函數(shù)就是閉包

基本概念

閉包是可以包含自由(未綁定到特定對(duì)象)變量的代碼塊,這些變量不在這個(gè)代碼塊內(nèi)或者任何全局上下文中定義,而是在定義代碼塊的環(huán)境中定義。要執(zhí)行的代碼塊(由于自由變量包含
在代碼塊中,所以這些自由變量以及它們引用的對(duì)象沒(méi)有被釋放)為自由變量提供綁定的計(jì)算環(huán)境(作用域)。

閉包的價(jià)值

閉包的價(jià)值在于可以作為函數(shù)對(duì)象或者匿名函數(shù),對(duì)于類(lèi)型系統(tǒng)而言,這意味著不僅要表示數(shù)據(jù)還要表示代碼。支持閉包的多數(shù)語(yǔ)言都將函數(shù)作為第一級(jí)對(duì)象,就是說(shuō)這些函數(shù)可以存儲(chǔ)到
變量中作為參數(shù)傳遞給其他函數(shù),最重要的是能夠被函數(shù)動(dòng)態(tài)創(chuàng)建和返回。

Go語(yǔ)言中的閉包

Go語(yǔ)言中的閉包同樣也會(huì)引用到函數(shù)外的變量。閉包的實(shí)現(xiàn)確保只要閉包還被使用,那么被閉包引用的變量會(huì)一直存在。例:

// closure.go
package main

import (
    "fmt"
)

func main() {
    var j int = 5

    a := func() func() {
        var i int = 10
        return func() {
            fmt.Printf("i, j: %d, %d\n", i, j)
        }
    }()  //末尾的括號(hào)表明匿名函數(shù)被調(diào)用,并將返回的函數(shù)指針賦給變量a

    a()

    j *= 2

    a()
}

輸出:
i, j: 10, 5
i, j: 10, 10

Go語(yǔ)言支持匿名函數(shù),即函數(shù)可以像普通變量一樣被傳遞或使用。

閉包是“函數(shù)”和“引用環(huán)境”組成的整體。

func anonymous(n int) func() {
    return func() {
        n++ //對(duì)外部變量加1
        fmt.Println(n)
    }
}
func anonymous2(n int) func() {
    sum := n
    a := func() { //把匿名函數(shù)作為值賦給變量a(Go不允許函數(shù)嵌套,但你可以利用匿名函數(shù)實(shí)現(xiàn)函數(shù)嵌套)
        fmt.Println(sum + 1) //調(diào)用本函數(shù)外的變量,這里沒(méi)有()匿名函數(shù)不會(huì)馬上執(zhí)行
    }
    return a
}

  fmt.Println("---------anonymous func--------")
    anony := anonymous(10)
    anony()
    anony1 := anonymous(20)
    anony1()
    /**
    *再次調(diào)用anony()函數(shù),結(jié)果是12,由此得出以下兩點(diǎn)
    * 1、內(nèi)函數(shù)對(duì)外函數(shù)的變量的修改,是對(duì)變量的引用
    * 2、變量被引用后,它所在的函數(shù)結(jié)束,該變量不會(huì)馬上銷(xiāo)毀
    **/
    anony()
    anony1()
    fmt.Println("---------anonymous2----------")
    an := anonymous2(10)
    an()
    an2 := anonymous2(20)
    an2()
    an()
    an2()
    
    輸出:

    ---------anonymous func--------
    11
    21
    12
    22
    ---------anonymous2----------
    11
    21
    11
    21

閉包函數(shù)出現(xiàn)的條件:
1.被嵌套的函數(shù)引用到非本函數(shù)的外部變量,而且這外部變量不是“全局變量”;
2.嵌套的函數(shù)被獨(dú)立了出來(lái)(被父函數(shù)返回或賦值 變成了獨(dú)立的個(gè)體), 而被引用的變量所在的父函數(shù)已結(jié)束。
對(duì)象是附有行為的數(shù)據(jù),而閉包是附有數(shù)據(jù)的行為。

匿名函數(shù)執(zhí)行

匿名函數(shù)最后括號(hào)中加參數(shù),匿名函數(shù)立即執(zhí)行,沒(méi)有括號(hào)或括號(hào)中為空,則需要傳參。例:

fmt.Println("-----------匿名函數(shù)的執(zhí)行----------")
    m, n := func(i, j int) (m, n int) { // x y 為函數(shù)返回值
        return j, i
    }(1, 9) // 直接創(chuàng)建匿名函數(shù)并執(zhí)行

    fmt.Println(m, n)

    f := func(i, j int) (result int) { // f 為函數(shù)地址
        result = i + j
        return result
    }

    fmt.Println(f(1, 2))
    
輸出:
-----------匿名函數(shù)的執(zhí)行----------
9 1
3

錯(cuò)誤: expression in go/defer must be function call

go關(guān)鍵字后跟匿名函數(shù)報(bào)錯(cuò): expression in go/defer must be function call,在匿名函數(shù)后加括號(hào)則可。例:

    func smtp() error {
        return nil
    }
  go func() {
        err := smtp()
        if err != nil {
            fmt.Printf(err.Error())
        }
    }()

若去掉上面代碼中的空括號(hào)會(huì)報(bào)錯(cuò)。
加()封裝成表達(dá)式。

參考資料:

  1. http://blog.sina.com.cn/s/blog_487109d101018fcx.html
  2. http://www.golangtc.com/t/5325047a320b523f0a00008b
  3. 《GO語(yǔ)言編程》
  4. http://www.cnblogs.com/ruixiazhixia/p/6024758.html
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

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