golang 函數二 (匿名函數和閉包)

來源:互聯網
上載者:User
這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。

匿名函數就是沒有定義函數名稱的函數。我們可以在函數內部定義匿名函數,也叫函數嵌套。

匿名函數可以直接被調用,也可以賦值給變數、作為參數或傳回值。比如:

func聽main(){聽聽聽聽func(s聽string){聽聽聽聽聽//直接被調用聽聽聽聽聽聽聽聽println(s)聽聽聽聽}("hello聽gopher!!!")聽聽聽聽/*聽聽聽聽func(s聽string){聽聽聽聽聽//未被調用聽聽聽聽聽聽聽聽println(s)聽聽聽聽}聽聽聽聽*/}func聽main(){聽聽聽聽hi聽:=聽func(s聽string){聽聽聽//賦值給變數聽聽聽聽聽聽聽聽println(s)聽聽聽聽}聽聽聽聽hi("hello聽gopher!!!")}func聽test(f聽func(string)){聽聽聽聽f("hello聽gopher!!!")}func聽main(){聽聽聽聽hi聽:=聽func(s聽string){聽聽聽聽聽聽聽聽println(s)聽聽聽聽}聽聽聽聽test(hi)聽聽聽聽聽//作為參數}func聽test()func(string){聽聽聽聽hi聽:=聽func(s聽string){聽聽聽//作為傳回值聽聽聽聽聽聽聽聽println(s)聽聽聽聽}聽聽聽聽return聽hi}func聽main(){聽聽聽聽f聽:=聽test()聽聽聽聽f("hello聽gopher!!!")}

普通函數和匿名函數都可以作為結構體的欄位,比如:

{聽聽聽聽type聽calc聽struct{聽聽聽聽聽聽聽聽mul聽func(x,y聽int)int聽聽聽聽}聽聽聽聽x聽:=聽calc{聽聽聽聽聽聽聽聽mul:聽func(x,y聽int)int{聽聽聽聽聽聽聽聽聽聽聽聽return聽(x*y)聽聽聽聽聽聽聽聽},聽聽聽聽}聽聽聽聽println(x.mul(2,3))}

也可以經channel(通道)傳遞,比如:

{聽聽聽聽c聽:=聽make(chan聽func(int,聽int)int,聽2)聽聽聽聽c聽<-聽func(x,y聽int)聽int聽{return聽x聽+聽y}聽聽聽聽println((<-c)(2,3))}

閉包(closure)

閉包是指在上下文中引用了自由變數(未綁定到特定對象)的代碼塊(函數),或者說是代碼塊(函數)與和引用環境的組合體。比如:

func聽intSeq()func()int{聽聽聽聽i聽:=聽0聽聽聽聽println(&i)聽聽聽聽return聽func()int{聽聽聽聽聽聽聽聽i聽+=聽1聽聽聽聽聽聽聽聽println(&i,i)聽聽聽聽聽聽聽聽return聽i聽聽聽聽}聽聽聽}聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽func聽main(){聽聽聽聽nextInt聽:=聽intSeq()聽聽聽聽fmt.Println(nextInt())聽聽聽聽fmt.Println(nextInt())聽聽聽聽fmt.Println(nextInt())聽聽聽聽newInt聽:=聽intSeq()聽聽聽聽fmt.Println(newInt())}輸出:0xc42000a3200xc42000a320聽110xc42000a320聽220xc42000a320聽330xc42007a0100xc42007a010聽11

當nextInt函數返回後,通過輸出指標,我們可以看出函數在main運行時,依然引用的是原環境變數指標,這種現象稱作閉包。所以說,閉包是函數和引用環境變數的組合體。

因為閉包是通過指標引用環境變數,那麼就會導致該變數的生命週期

變長,甚至被分配到堆記憶體。如果多個匿名函數引用同一個環境變數,會讓事情變得更加複雜,比如:

func聽test()[]func(){聽聽聽聽var聽s聽[]func()聽聽聽聽for聽i:=聽0;i聽<聽3;i++{聽聽聽聽聽聽聽聽s聽=聽聽append(s,聽func(){聽聽聽聽聽聽聽聽聽聽聽聽println(&i聽,聽i)聽聽聽聽聽聽聽聽})聽聽聽聽}聽聽聽聽return聽s}func聽main(){聽聽聽聽funcSlice聽:=聽test()聽聽聽聽for聽_聽,聽f聽:=聽range聽funcSlice{聽聽聽聽聽聽聽聽f()聽聽聽聽}}輸出:0xc42000a320聽30xc42000a320聽30xc42000a320聽3

解決方案就是每次用不同的環境變數或參數賦值,比如修改後的test函數:

func聽test()[]func(){聽聽聽聽var聽s聽[]func()聽聽聽聽for聽i:=聽0;i聽<聽3;i++{聽聽聽聽聽聽聽聽x聽:=聽i聽聽聽聽聽聽聽聽s聽=聽聽append(s,聽func(){聽聽聽聽聽聽聽聽聽聽聽聽println(&x聽,聽x)聽聽聽聽聽聽聽聽})聽聽聽聽}聽聽聽聽return聽s}

閉包在不用傳遞參數的情況下就可以讀取和修改環境變數,當然我們是要為這種遍曆付出代價的,所以日常開發中,在高並發服務

的情境下建議慎用,除非你明確你的需求必須這樣做。

本文出自 “博學於文,約之於禮” 部落格,轉載請與作者聯絡!

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.