国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > Golang > 正文

深入理解Go語言中的閉包

2020-04-01 19:06:11
字體:
來源:轉載
供稿:網友

閉包

在函數編程中經常用到閉包,閉包是什?它是怎么產生的及用來解決什么問題呢?先給出閉包的字面定義:閉包是由函數及其相關引用環境組合而成的實體(即:閉包=函數+引用環境)。這個從字面上很難理解,特別對于一直使用命令式語言進行編程的程序員們。

Go語言中的閉包

先看一個demo:

func f(i int) func() int { return func() int { i++ return i }}

函數f返回了一個函數,返回的這個函數就是一個閉包。這個函數中本身是沒有定義變量i的,而是引用了它所在的環境(函數f)中的變量i。

我們再看一下效果:

c1 := f(0)c2 := f(0)c1() // reference to i, i = 0, return 1c2() // reference to another i, i = 0, return 1

c1跟c2引用的是不同的環境,在調用i++時修改的不是同一個i,因此兩次的輸出都是1。函數f每進入一次,就形成了一個新的環境,對應的閉包中,函數都是同一個函數,環境卻是引用不同的環境。

變量i是函數f中的局部變量,假設這個變量是在函數f的棧中分配的,是不可以的。因為函數f返回以后,對應的棧就失效了,f返回的那個函數中變量i就引用一個失效的位置了。所以閉包的環境中引用的變量不能夠在棧上分配。

escape analyze

在繼續研究閉包的實現之前,先看一看Go的一個語言特性:

func f() *Cursor { var c Cursor c.X = 500 noinline() return &c}

Cursor是一個結構體,這種寫法在C語言中是不允許的,因為變量c是在棧上分配的,當函數f返回后c的空間就失效了。但是,在Go語言規范中有說明,這種寫法在Go語言中合法的。語言會自動地識別出這種情況并在堆上分配c的內存,而不是函數f的棧上。

為了驗證這一點,可以觀察函數f生成的匯編代碼:

MOVQ $type."".Cursor+0(SB),(SP) // 取變量c的類型,也就是CursorPCDATA $0,$16PCDATA $1,$0CALL ,runtime.new(SB) // 調用new函數,相當于new(Cursor)PCDATA $0,$-1MOVQ 8(SP),AX // 取c.X的地址放到AX寄存器MOVQ $500,(AX) // 將AX存放的內存地址的值賦為500MOVQ AX,"".~r0+24(FP)ADDQ $16,SP

識別出變量需要在堆上分配,是由編譯器的一種叫escape analyze的技術實現的。

如果輸入命令:

go build --gcflags=-m main.go

可以看到輸出:

GO語言閉包,golang閉包,go.,閉包

注意:最后兩行,標識c逃逸了,被移動到堆中。escape analyze可以分析出變量的作用范圍,這是對垃圾回收很重要的一項技術。

總結

以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作能帶來一定的幫助,如果有疑問大家可以留言交流。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 军事| 福建省| 肃南| 来宾市| 西昌市| 佳木斯市| 彭泽县| 宜川县| 梧州市| 岳普湖县| 金秀| 呈贡县| 南华县| 民权县| 扎鲁特旗| 冷水江市| 邵阳市| 太康县| 诏安县| 山东省| 梅州市| 江都市| 揭东县| 阳新县| 石景山区| 江孜县| 肇源县| 天峻县| 年辖:市辖区| 凌云县| 淮滨县| 庆云县| 濮阳县| 新昌县| 贵州省| 临沂市| 贵港市| 华阴市| 嘉祥县| 山阳县| 彩票|