Go匿名函數


1、GO語言的匿名函數就是閉包

基本概念
  閉包是可以包含自由(未綁定到特定對象)變量的代碼塊,這些變量不在這個代碼塊內或者任何全局上下文中定義,而是在定義代碼塊的環境中定義。要執行的代碼塊(由於自由變量包含
在代碼塊中,所以這些自由變量以及它們引用的對象沒有被釋放)為自由變量提供綁定的計算環境(作用域)。
閉包的價值
  閉包的價值在於可以作為函數對象或者匿名函數,對於類型系統而言,這意味着不僅要表示數據還要表示代碼。支持閉包的多數語言都將函數作為第一級對象,就是說這些函數可以存儲到
變量中作為參數傳遞給其他函數,最重要的是能夠被函數動態創建和返回。

Go語言中的閉包

  Go語言中的閉包同樣也會引用到函數外的變量。閉包的實現確保只要閉包還被使用,那么被閉包引用的變量會一直存在。例:

// 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)
        }
    }()  //末尾的括號表明匿名函數被調用,並將返回的函數指針賦給變量a

    a()

    j *= 2

    a()
}

輸出:

i, j: 10, 5
i, j: 10, 10

2、Go語言支持匿名函數,即函數可以像普通變量一樣被傳遞或使用

閉包是“函數”和“引用環境”組成的整體。

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

  fmt.Println("---------anonymous func--------")
    anony := anonymous(10)
    anony()
    anony1 := anonymous(20)
    anony1()
    /**
    *再次調用anony()函數,結果是12,由此得出以下兩點
    * 1、內函數對外函數的變量的修改,是對變量的引用
    * 2、變量被引用后,它所在的函數結束,該變量不會馬上銷毀
    **/
    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
閉包函數出現的條件
1.被嵌套的函數引用到非本函數的外部變量,而且這外部變量不是“全局變量”;
2.嵌套的函數被獨立了出來(被父函數返回或賦值 變成了獨立的個體),  而被引用的變量所在的父函數已結束。

對象是附有行為的數據,而閉包是附有數據的行為

3、匿名函數執行

  匿名函數最后括號中加參數,匿名函數立即執行,沒有括號或括號中為空,則需要傳參。例:

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

    fmt.Println(m, n)

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

    fmt.Println(f(1, 2))

輸出:

-----------匿名函數的執行----------
9 1
3

4、錯誤: expression in go/defer must be function call

  go關鍵字后跟匿名函數報錯: expression in go/defer must be function call,在匿名函數后加括號則可。例:

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

  若去掉上面代碼中的空括號會報錯。

  加()封裝成表達式。

  

參考資料

  1、http://blog.sina.com.cn/s/blog_487109d101018fcx.html

  2、http://www.golangtc.com/t/5325047a320b523f0a00008b

  3、《GO語言編程》

  4、http://www.cnblogs.com/ruixiazhixia/p/6024758.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM