最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Go語(yǔ)言中的閉包詳解

 更新時(shí)間:2022年07月16日 11:31:46   作者:奮斗的大橙子  
本文詳細(xì)講解了Go語(yǔ)言中的閉包,文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下

一、函數(shù)的變量作用域和可見(jiàn)性

1.全局變量在main函數(shù)執(zhí)行之前初始化,全局可見(jiàn)

2.局部變量在函數(shù)內(nèi)部或者if、for等語(yǔ)句塊有效,使用之后外部不可見(jiàn)

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

4.可見(jiàn)性:

包內(nèi)任何變量或函數(shù)都是能訪問(wèn)的。

包外的話,首字母大寫是可以訪問(wèn)的,首字母小寫的表示私有的不能被外部調(diào)用。

二、匿名函數(shù)

1.Go語(yǔ)言中函數(shù)也是一種類型,所以可以用一個(gè)函數(shù)類型的變量進(jìn)行接收。

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

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

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

3.下面一個(gè)例子結(jié)合defer來(lái)看一下,這三個(gè)輸出都是什么

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初始化后的值,最后一個(gè)也一定是for循環(huán)之后的值10,

主要就是匿名函數(shù)執(zhí)行之后的值,有意思是10,說(shuō)明訪問(wèn)了匿名函數(shù)外部的i,這就涉及到了閉包

運(yùn)行結(jié)果如下:

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

4.既然函數(shù)也是一種類型,那么就可以把函數(shù)當(dāng)做參數(shù)進(jìn)行輸入、輸出了。(感覺(jué)有點(diǎn)類似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)
}

結(jié)果:

x=3, y=1

三、閉包

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

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

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

換句話說(shuō),這個(gè)匿名函數(shù)和這個(gè)自由變量x組成了一個(gè)整體,只要是在這個(gè)整體的生命周期內(nèi)這個(gè)x都是有效的。

下面使用一下這個(gè)Adder函數(shù):

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

執(zhí)行結(jié)果

結(jié)果=1
 
結(jié)果=21
 
結(jié)果=321

正如上面所提到的,這個(gè)只要Addr() 也就是f這個(gè)對(duì)象沒(méi)有消亡,那么f中的這個(gè)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接收一個(gè)int類型參數(shù)base,然后返回一個(gè)func,這里這個(gè)匿名函數(shù)里面引用了這個(gè)參數(shù)base,那么這個(gè)參數(shù)base和匿名函數(shù)就形成了一個(gè)整體。

后面我們 tmp1被賦值為 Adder2(10) ,那么在tmp1這個(gè)對(duì)象的生命周期內(nèi),base是被初始化為10且一直存在,所以結(jié)果是 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的匿名函數(shù)也組成了一個(gè)實(shí)體也就是calc,所以在f1和f2的生命周期內(nèi),base一直存在,并被初始化成了10.

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

所以結(jié)果如下:

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)
}

上述代碼應(yīng)該結(jié)果是多少?我的猜想應(yīng)該是0、1、2、3、4

但是實(shí)際結(jié)果是:

5
5
5
5
5

為什么會(huì)出現(xiàn)這樣的情況?實(shí)際上面這里每一個(gè)go協(xié)程中的匿名函數(shù)和外部for循環(huán)的i也形成了閉包,因?yàn)閒or循環(huán)執(zhí)行比較快,所以go還沒(méi)來(lái)得及執(zhí)行就變成5了。

我在每一個(gè)go協(xié)程之后加一個(gè)延時(shí),結(jié)果就是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)
}

結(jié)果如下

0
1
2
3
4

問(wèn)題就在于不可能每次執(zhí)行都進(jìn)行延遲吧,所以需要做一件事情打破這個(gè)閉包。

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

    }
    time.Sleep(time.Second)
}

這里把i當(dāng)做參數(shù)傳入到匿名函數(shù)中,保證了每次循環(huán)傳的值都不一樣。

到此這篇關(guān)于Go語(yǔ)言閉包的文章就介紹到這了。希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • go-zero過(guò)載保護(hù)源碼解讀

    go-zero過(guò)載保護(hù)源碼解讀

    這篇文章主要為大家介紹了go-zero過(guò)載保護(hù)源碼解讀,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-08-08
  • golang切片拷貝的實(shí)現(xiàn)

    golang切片拷貝的實(shí)現(xiàn)

    在Golang中,切片的淺拷貝只復(fù)制指向?qū)ο蟮闹羔?而深拷貝則復(fù)制數(shù)據(jù)本身,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2024-10-10
  • 簡(jiǎn)介Go語(yǔ)言中的select語(yǔ)句的用法

    簡(jiǎn)介Go語(yǔ)言中的select語(yǔ)句的用法

    這篇文章主要介紹了簡(jiǎn)介Go語(yǔ)言中的select語(yǔ)句的用法,是golang入門學(xué)習(xí)中的基礎(chǔ)知識(shí),需要的朋友可以參考下
    2015-10-10
  • Golang中context包使用場(chǎng)景和示例詳解

    Golang中context包使用場(chǎng)景和示例詳解

    這篇文章結(jié)合示例代碼介紹了context包的幾種使用場(chǎng)景,文中有詳細(xì)的代碼示例,對(duì)學(xué)習(xí)或工作有一定的幫助,需要的朋友可以參考下
    2023-05-05
  • Golang中四種gRPC模式舉例詳解

    Golang中四種gRPC模式舉例詳解

    gRPC是一種進(jìn)程間通信技術(shù),在微服務(wù)和云原生領(lǐng)域都有著廣泛的應(yīng)用,下面這篇文章主要給大家介紹了關(guān)于Golang中四種gRPC模式的相關(guān)資料,文中通過(guò)代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2024-03-03
  • 使用go語(yǔ)言解析xml的實(shí)現(xiàn)方法(必看篇)

    使用go語(yǔ)言解析xml的實(shí)現(xiàn)方法(必看篇)

    下面小編就為大家?guī)?lái)一篇使用go語(yǔ)言解析xml的實(shí)現(xiàn)方法(必看篇)。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-06-06
  • Go語(yǔ)言實(shí)現(xiàn)Sm2加解密的示例代碼

    Go語(yǔ)言實(shí)現(xiàn)Sm2加解密的示例代碼

    本文主要介紹了Go語(yǔ)言實(shí)現(xiàn)Sm2加解密的示例代碼,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2023-03-03
  • Go語(yǔ)言中使用urfave/cli命令行框架

    Go語(yǔ)言中使用urfave/cli命令行框架

    這篇文章介紹了Go語(yǔ)言中使用urfave/cli命令行框架的方法,文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-07-07
  • Go實(shí)現(xiàn)各類限流的方法

    Go實(shí)現(xiàn)各類限流的方法

    這篇文章主要介紹了Go實(shí)現(xiàn)各類限流的方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2021-05-05
  • 探索分析Go?HTTP?GET請(qǐng)求發(fā)送body

    探索分析Go?HTTP?GET請(qǐng)求發(fā)送body

    這篇文章主要為大家介紹了探索分析Go?HTTP?GET請(qǐng)求發(fā)送body,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-11-11

最新評(píng)論

鞍山市| 六枝特区| 衡阳市| 墨脱县| 罗定市| 年辖:市辖区| 泌阳县| 东平县| 承德市| 准格尔旗| 昌乐县| 昂仁县| 宝清县| 舞钢市| 盐山县| 宣化县| 内黄县| 桓台县| 双流县| 万山特区| 大英县| 同仁县| 新源县| 吴堡县| 定州市| 花垣县| 绍兴市| 突泉县| 西畴县| 武冈市| 日照市| 南漳县| 南澳县| 延寿县| 通河县| 青龙| 任丘市| 莆田市| 五河县| 库尔勒市| 石首市|