中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Go語言中的閉包實例分析

發布時間:2022-07-18 10:16:33 來源:億速云 閱讀:137 作者:iii 欄目:開發技術

這篇文章主要介紹“Go語言中的閉包實例分析”的相關知識,小編通過實際案例向大家展示操作過程,操作方法簡單快捷,實用性強,希望這篇“Go語言中的閉包實例分析”文章能幫助大家解決問題。

一、函數的變量作用域和可見性

1.全局變量在main函數執行之前初始化,全局可見

2.局部變量在函數內部或者if、for等語句塊有效,使用之后外部不可見

3.全局變量和局部變量同名的情況下,局部變量生效。

4.可見性:

包內任何變量或函數都是能訪問的。

包外的話,首字母大寫是可以訪問的,首字母小寫的表示私有的不能被外部調用。

二、匿名函數

1.Go語言中函數也是一種類型,所以可以用一個函數類型的變量進行接收。

func anonyTest1(){
    fmt.Println("anonyTest1")
}
 
//將改函數賦值給一個變量f,執行f
func AnonyTest(){
    f:= anonyTest1
    f()
}

2.匿名函數就是不指定名稱的函數,如下就是匿名函數的使用

func AnonyTest2(){
    f:= func() {
        fmt.Println("AnonyTest2")
    }
    f()
 
    //或者
    func() {
        fmt.Println("AnonyTest2...")
    }()
}

3.下面一個例子結合defer來看一下,這三個輸出都是什么

func AnonyTest3(){
    var i=0
    defer func() {
        fmt.Printf("defer func i=%v \n",i)
    }()
 
     defer fmt.Printf("defer i=%v \n",i)
 
    for;i<10; i++{
    }
 
    fmt.Printf("i=%v \n",i)
}

從defer那篇文章我們知道 defer fmt.Printf("defer i=%v \n",i) 打印的就是i初始化后的值,最后一個也一定是for循環之后的值10,

主要就是匿名函數執行之后的值,有意思是10,說明訪問了匿名函數外部的i,這就涉及到了閉包

運行結果如下:

i=10
defer i=0
defer func i=10

4.既然函數也是一種類型,那么就可以把函數當做參數進行輸入、輸出了。(感覺有點類似C#里面的委托)

func Calc(a,b int, op func(int,int)int) int {
    return op(a,b)
}
 
func add(a,b int) int{
    return a+b
}
 
func sub(a,b int)int{
    return  a-b
}
 
func AnonyTest4(){
 
    var a = 2
    var b = 1
 
    var x = Calc(a,b,add)
    var y = Calc(a,b,sub)
 
    fmt.Printf("x=%v, y=%v \n",x,y)
}

結果:

x=3, y=1

三、閉包

閉包是由函數和與其相關的引用環境組合而成的實體(好抽象,難理解啊)

func Adder() func(int) int{
    var x int
    return func(d int) int{
        x+=d
        return x
    }
}

像上面這段代碼,我們可以看到定義了一個變量x,以及return中的匿名函數。我們可以看到匿名函數引用了外部的變量x,我們可以把這個x叫做自由變量。

換句話說,這個匿名函數和這個自由變量x組成了一個整體,只要是在這個整體的生命周期內這個x都是有效的。

下面使用一下這個Adder函數:

func ClosureDemo5(){
    var f = Adder()
    fmt.Printf("結果=%d\n",f(1))
    fmt.Printf("結果=%d\n",f(20))
    fmt.Printf("結果=%d\n",f(300))
}

執行結果

結果=1
 
結果=21
 
結果=321

正如上面所提到的,這個只要Addr() 也就是f這個對象沒有消亡,那么f中的這個x就始終存在,也就是為什么第二次是21,第三次是321的原因了。

其他例子:

例子1:

func Adder2(base int) func(int)int{
    return func(i int) int{
        base += i
        return base
    }
}
 
func main(){
    tmp1 := Adder2(10)
    fmt.Println(tmp1(1),tmp1(2))
 
    tmp2 := Adder2(100)
    fmt.Println(tmp2(10),tmp2(20))
}

這里Adder2接收一個int類型參數base,然后返回一個func,這里這個匿名函數里面引用了這個參數base,那么這個參數base和匿名函數就形成了一個整體。

后面我們 tmp1被賦值為 Adder2(10) ,那么在tmp1這個對象的生命周期內,base是被初始化為10且一直存在,所以結果是 11 和 13,同理后面是 110 和 130

例子2:

func calc(base int) (func(int)int,func(int)int){
    add:= func(i int)int{
        base +=i
        return base
    }
    sub:= func(i int)int{
        base -= i
        return base
    }
    return add,sub
}
 
 
func main(){
    f1,f2 := calc(10)
    fmt.Println(f1(1),f2(2))
    fmt.Println(f1(3),f2(4))
    fmt.Println(f1(5),f2(6))
    fmt.Println(f1(7),f2(8))
}

分析一下:

這里base和 add以及sub的匿名函數也組成了一個實體也就是calc,所以在f1和f2的生命周期內,base一直存在,并被初始化成了10.

所以結果就是 f1(1) 就是10+1 =11 而 f2(2)就是 11-2 = 9,其他同理。

所以結果如下:

11 9 
12 8 
13 7 
14 6 

閉包的副作用!

func main(){
    for i:=0;i<5;i++{
        go func(x int){
            fmt.Println(x)
        }(i)
 
    }
    time.Sleep(time.Second)
}

上述代碼應該結果是多少?我的猜想應該是0、1、2、3、4

但是實際結果是:

5
5
5
5
5

為什么會出現這樣的情況?實際上面這里每一個go協程中的匿名函數和外部for循環的i也形成了閉包,因為for循環執行比較快,所以go還沒來得及執行就變成5了。

我在每一個go協程之后加一個延時,結果就是0,1,2,3,4了。

func main(){
    for i:=0;i<5;i++{
        go func(){
            fmt.Println(i)
        }()
            time.Sleep(time.Second)
    }
    time.Sleep(time.Second)
}

結果如下

0
1
2
3
4

問題就在于不可能每次執行都進行延遲吧,所以需要做一件事情打破這個閉包。

func main(){
    for i:=0;i<5;i++{
        go func(x int){
            fmt.Println(x)
        }(i)

    }
    time.Sleep(time.Second)
}

這里把i當做參數傳入到匿名函數中,保證了每次循環傳的值都不一樣。

關于“Go語言中的閉包實例分析”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識,可以關注億速云行業資訊頻道,小編每天都會為大家更新不同的知識點。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

澳门| 河北省| 阜阳市| 合江县| 汉沽区| 城固县| 綦江县| 集贤县| 尚义县| 弥渡县| 阳泉市| 新昌县| 汉中市| 沅陵县| 乐山市| 思南县| 延津县| 鄂尔多斯市| 湘乡市| 赣榆县| 东源县| 惠安县| 大埔区| 潍坊市| 秭归县| 吉林市| 泰顺县| 延边| 东平县| 越西县| 定兴县| 密云县| 祁阳县| 耒阳市| 柘荣县| 会东县| 滦南县| 扶风县| 大埔区| 两当县| 凭祥市|