0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫(xiě)文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

帶你了解go語(yǔ)言中的閉包

Linux愛(ài)好者 ? 來(lái)源:gitbooks ? 作者:gitbooks ? 2021-11-02 15:27 ? 次閱讀

導(dǎo)讀】什么是閉包?什么場(chǎng)景下會(huì)用閉包?本文對(duì) go 語(yǔ)言中的閉包做了詳細(xì)介紹。

閉包是由函數(shù)及其相關(guān)引用環(huán)境組合而成的實(shí)體(即:閉包=函數(shù)+引用環(huán)境)。

Go中的閉包

閉包是函數(shù)式語(yǔ)言中的概念,沒(méi)有研究過(guò)函數(shù)式語(yǔ)言的用戶可能很難理解閉包的強(qiáng)大,相關(guān)的概念超出了本書(shū)的范圍。Go語(yǔ)言是支持閉包的,這里只是簡(jiǎn)單地講一下在Go語(yǔ)言中閉包是如何實(shí)現(xiàn)的。

funcf(iint)func()int{
returnfunc()int{
i++
returni
}
}

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

c1:=f(0)
c2:=f(0)
c1()//referencetoi,i=0,return1
c2()//referencetoanotheri,i=0,return1

c1跟c2引用的是不同的環(huán)境,在調(diào)用i++時(shí)修改的不是同一個(gè)i,因此兩次的輸出都是1。函數(shù)f每進(jìn)入一次,就形成了一個(gè)新的環(huán)境,對(duì)應(yīng)的閉包中,函數(shù)都是同一個(gè)函數(shù),環(huán)境卻是引用不同的環(huán)境。

變量i是函數(shù)f中的局部變量,假設(shè)這個(gè)變量是在函數(shù)f的棧中分配的,是不可以的。因?yàn)楹瘮?shù)f返回以后,對(duì)應(yīng)的棧就失效了,f返回的那個(gè)函數(shù)中變量i就引用一個(gè)失效的位置了。所以閉包的環(huán)境中引用的變量不能夠在棧上分配。

escape analyze

在繼續(xù)研究閉包的實(shí)現(xiàn)之前,先看一看Go的一個(gè)語(yǔ)言特性:

funcf()*Cursor{
varcCursor
c.X=500
noinline()
return&c
}

Cursor是一個(gè)結(jié)構(gòu)體,這種寫(xiě)法在C語(yǔ)言中是不允許的,因?yàn)樽兞縞是在棧上分配的,當(dāng)函數(shù)f返回后c的空間就失效了。但是,在Go語(yǔ)言規(guī)范中有說(shuō)明,這種寫(xiě)法在Go語(yǔ)言中合法的。語(yǔ)言會(huì)自動(dòng)地識(shí)別出這種情況并在堆上分配c的內(nèi)存,而不是函數(shù)f的棧上。

為了驗(yàn)證這一點(diǎn),可以觀察函數(shù)f生成的匯編代碼:

MOVQ$type."".Cursor+0(SB),(SP)//取變量c的類型,也就是Cursor
PCDATA$0,$16
PCDATA$1,$0
CALL,runtime.new(SB)//調(diào)用new函數(shù),相當(dāng)于new(Cursor)
PCDATA$0,$-1
MOVQ8(SP),AX//取c.X的地址放到AX寄存器
MOVQ$500,(AX)//將AX存放的內(nèi)存地址的值賦為500
MOVQAX,"".~r0+24(FP)
ADDQ$16,SP

識(shí)別出變量需要在堆上分配,是由編譯器的一種叫escape analyze的技術(shù)實(shí)現(xiàn)的。如果輸入命令:

gobuild--gcflags=-mmain.go

可以看到輸出:

./main.gomovedtoheap:c
./main.go&cescapestoheap

表示c逃逸了,被移到堆中。escape analyze可以分析出變量的作用范圍,這是對(duì)垃圾回收很重要的一項(xiàng)技術(shù)。

閉包結(jié)構(gòu)體

回到閉包的實(shí)現(xiàn)來(lái),前面說(shuō)過(guò),閉包是函數(shù)和它所引用的環(huán)境。那么是不是可以表示為一個(gè)結(jié)構(gòu)體呢:

typeClosurestruct{
Ffunc()()
i*int
}

事實(shí)上,Go在底層確實(shí)就是這樣表示一個(gè)閉包的。讓我們看一下匯編代碼:

funcf(iint)func()int{
returnfunc()int{
i++
returni
}
}


MOVQ$type.int+0(SB),(SP)
PCDATA$0,$16
PCDATA$1,$0
CALL,runtime.new(SB)//是不是很熟悉,這一段就是i=new(int)
...
MOVQ$type.struct{Fuintptr;A0*int}+0(SB),(SP)//這個(gè)結(jié)構(gòu)體就是閉包的類型
...
CALL,runtime.new(SB)//接下來(lái)相當(dāng)于new(Closure)
PCDATA$0,$-1
MOVQ8(SP),AX
NOP,
MOVQ$"".func·001+0(SB),BP
MOVQBP,(AX)//函數(shù)地址賦值給Closure的F部分
NOP,
MOVQ"".&i+16(SP),BP//將堆中new的變量i的地址賦值給Closure的值部分
MOVQBP,8(AX)
MOVQAX,"".~r1+40(FP)
ADDQ$24,SP
RET,

其中func·001是另一個(gè)函數(shù)的函數(shù)地址,也就是f返回的那個(gè)函數(shù)。

小結(jié)

  1. Go語(yǔ)言支持閉包
  2. Go語(yǔ)言能通過(guò)escape analyze識(shí)別出變量的作用域,自動(dòng)將變量在堆上分配。將閉包環(huán)境變量在堆上分配是Go實(shí)現(xiàn)閉包的基礎(chǔ)。
  3. 返回閉包時(shí)并不是單純返回一個(gè)函數(shù),而是返回了一個(gè)結(jié)構(gòu)體,記錄下函數(shù)返回地址和引用的環(huán)境中的變量地址。

tiancaiamao.gitbooks.io/go-internals/content/zh/03.6.html

責(zé)任編輯:haq
聲明:本文內(nèi)容及配圖由入駐作者撰寫(xiě)或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 語(yǔ)言
    +關(guān)注

    關(guān)注

    1

    文章

    97

    瀏覽量

    24468
  • 函數(shù)
    +關(guān)注

    關(guān)注

    3

    文章

    4374

    瀏覽量

    64423

原文標(biāo)題:Golang 閉包的實(shí)現(xiàn)

文章出處:【微信號(hào):LinuxHub,微信公眾號(hào):Linux愛(ài)好者】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏

    評(píng)論

    相關(guān)推薦
    熱點(diǎn)推薦

    EE-62:在C語(yǔ)言中訪問(wèn)短字內(nèi)存

    電子發(fā)燒友網(wǎng)站提供《EE-62:在C語(yǔ)言中訪問(wèn)短字內(nèi)存.pdf》資料免費(fèi)下載
    發(fā)表于 01-07 14:02 ?0次下載
    EE-62:在C<b class='flag-5'>語(yǔ)言中</b>訪問(wèn)短字內(nèi)存

    EE-128:C語(yǔ)言中的DSP:從C調(diào)用匯編類成員函數(shù)

    電子發(fā)燒友網(wǎng)站提供《EE-128:C語(yǔ)言中的DSP:從C調(diào)用匯編類成員函數(shù).pdf》資料免費(fèi)下載
    發(fā)表于 01-07 13:48 ?0次下載
    EE-128:C<b class='flag-5'>語(yǔ)言中</b>的DSP:從C調(diào)用匯編類成員函數(shù)

    霍爾元件常開(kāi)和常怎么區(qū)分

    霍爾元件是一種基于霍爾效應(yīng)的磁傳感器,它通過(guò)感應(yīng)磁場(chǎng)的變化來(lái)輸出相應(yīng)的電信號(hào)。在討論如何區(qū)分霍爾元件的常開(kāi)和常之前,我們需要了解一些基本概念。霍爾元件一般有NPN和PNP兩種輸出類型,而常開(kāi)和常
    的頭像 發(fā)表于 12-18 10:08 ?888次閱讀

    影目科技發(fā)布全球首款同傳翻譯眼鏡INMO GO2

    近日,搭載紫光展銳W517芯片平臺(tái)的INMO GO2由影目科技正式推出。作為全球首款專為商務(wù)場(chǎng)景設(shè)計(jì)的智能翻譯眼鏡,INMO GO2 以“快、準(zhǔn)、穩(wěn)”三大核心優(yōu)勢(shì),突破傳統(tǒng)翻譯產(chǎn)品局限,為全球商務(wù)人士帶來(lái)高效、自然、穩(wěn)定的跨語(yǔ)言
    的頭像 發(fā)表于 12-11 10:00 ?1120次閱讀

    深入理解C語(yǔ)言:循環(huán)語(yǔ)句的應(yīng)用與優(yōu)化技巧

    能讓你的代碼更加簡(jiǎn)潔明了,還能顯著提升程序執(zhí)行效率。本文將詳細(xì)介紹C語(yǔ)言中的三種常見(jiàn)循環(huán)結(jié)構(gòu)——while循環(huán)、for循環(huán)和do...while循環(huán),帶你深入理解它
    的頭像 發(fā)表于 12-07 01:11 ?561次閱讀
    深入理解C<b class='flag-5'>語(yǔ)言</b>:循環(huán)語(yǔ)句的應(yīng)用與優(yōu)化技巧

    C語(yǔ)言中申請(qǐng)的堆內(nèi)存能不能自動(dòng)釋放

    C語(yǔ)言中申請(qǐng)的堆內(nèi)存能不能自動(dòng)釋放?每次都要手動(dòng) free 太麻煩,也容易忘記。 學(xué)過(guò) C++ 的同學(xué),應(yīng)該首先能想到智能指針。 但是這是C語(yǔ)言,沒(méi)有類和對(duì)象、構(gòu)造析構(gòu)這些技術(shù),想要自動(dòng)釋放很難
    的頭像 發(fā)表于 11-27 09:33 ?488次閱讀

    C語(yǔ)言中的頭文件能不能重復(fù)包含

    C語(yǔ)言中的頭文件能不能重復(fù)包含? 比如代碼寫(xiě)成這樣,stdio.h 連續(xù)包含了兩次。 #include #include int main(){ printf("helloworld
    的頭像 發(fā)表于 11-26 17:19 ?541次閱讀

    在學(xué)習(xí)go語(yǔ)言的過(guò)程踩過(guò)的坑

    作為一個(gè)5年的phper,這兩年公司和個(gè)人都在順應(yīng)技術(shù)趨勢(shì),新項(xiàng)目慢慢從php轉(zhuǎn)向了go語(yǔ)言,從2021年到現(xiàn)在,筆者手上也先后開(kāi)發(fā)了兩個(gè)go項(xiàng)目。在學(xué)習(xí)go
    的頭像 發(fā)表于 11-11 09:22 ?427次閱讀

    C語(yǔ)言中的socket編程基礎(chǔ)

    Socket編程簡(jiǎn)介 Socket是一種通信機(jī)制,允許程序之間進(jìn)行通信。在C語(yǔ)言中,socket編程是網(wǎng)絡(luò)編程的基礎(chǔ)。通過(guò)使用socket,程序可以發(fā)送和接收數(shù)據(jù),實(shí)現(xiàn)不同計(jì)算機(jī)之間的通信
    的頭像 發(fā)表于 11-01 16:51 ?1118次閱讀

    go語(yǔ)言如何解決并發(fā)問(wèn)題

    作為一個(gè)后端開(kāi)發(fā),日常工作中接觸最多的兩門語(yǔ)言就是PHP和GO了。無(wú)可否認(rèn),PHP確實(shí)是最好的語(yǔ)言(手動(dòng)狗頭哈哈),寫(xiě)起來(lái)真的很舒爽,沒(méi)有任何心智負(fù)擔(dān),字符串和整型壓根就不用區(qū)分,開(kāi)發(fā)速度真的是比
    的頭像 發(fā)表于 10-23 13:38 ?446次閱讀
    <b class='flag-5'>go</b><b class='flag-5'>語(yǔ)言</b>如何解決并發(fā)問(wèn)題

    c語(yǔ)言中從左到右結(jié)合怎么看

    在C語(yǔ)言中,操作符的結(jié)合性(Associativity)是指當(dāng)操作符在表達(dá)式中連續(xù)出現(xiàn)時(shí),它們?nèi)绾闻c操作數(shù)結(jié)合的順序。對(duì)于大多數(shù)二元操作符(即需要兩個(gè)操作數(shù)的操作符),C語(yǔ)言遵循兩種基本的結(jié)合方式
    的頭像 發(fā)表于 08-20 11:42 ?1554次閱讀

    磁性開(kāi)關(guān)常與常開(kāi)型號(hào)區(qū)別

    磁性開(kāi)關(guān),也稱為磁簧開(kāi)關(guān)或磁控開(kāi)關(guān),是一種利用磁場(chǎng)來(lái)控制電路通斷的開(kāi)關(guān)元件。它主要由磁簧管、觸點(diǎn)和外殼等部分組成。根據(jù)觸點(diǎn)的狀態(tài),磁性開(kāi)關(guān)可以分為常型和常開(kāi)型兩種類型。 一、常型磁性開(kāi)關(guān) 常
    的頭像 發(fā)表于 08-19 10:38 ?3215次閱讀

    三十分鐘入門基礎(chǔ)Go Java小子版

    前言 Go語(yǔ)言定義 Go(又稱 Golang)是 Google 的 Robert Griesemer,Rob Pike 及 Ken Thompson 開(kāi)發(fā)的一種靜態(tài)、強(qiáng)類型、編譯型語(yǔ)言
    的頭像 發(fā)表于 08-12 14:32 ?955次閱讀
    三十分鐘入門基礎(chǔ)<b class='flag-5'>Go</b> Java小子版

    技術(shù)干貨驛站 ▏深入理解C語(yǔ)言:基本數(shù)據(jù)類型和變量

    在C語(yǔ)言中,數(shù)據(jù)類型和變量是編程的基礎(chǔ),也是理解更復(fù)雜概念的關(guān)鍵。數(shù)據(jù)類型決定了變量的內(nèi)存分配、存儲(chǔ)范圍和操作方式,而變量則是存儲(chǔ)數(shù)據(jù)的容器。本篇文章將從基本數(shù)據(jù)類型和變量?jī)蓚€(gè)方面,帶你深入了解C
    的頭像 發(fā)表于 07-26 17:53 ?2665次閱讀
    技術(shù)干貨驛站 ▏深入理解C<b class='flag-5'>語(yǔ)言</b>:基本數(shù)據(jù)類型和變量

    小型繼電器的常開(kāi)常點(diǎn)是什么

    小型繼電器是一種常見(jiàn)的電子元件,廣泛應(yīng)用于自動(dòng)控制、電力系統(tǒng)、通信設(shè)備等領(lǐng)域。在繼電器的工作原理中,常開(kāi)常點(diǎn)是其核心組成部分,對(duì)于繼電器的正常工作至關(guān)重要。本文將詳細(xì)介紹小型繼電器的常開(kāi)常點(diǎn)
    的頭像 發(fā)表于 06-29 10:20 ?1604次閱讀

    電子發(fā)燒友

    中國(guó)電子工程師最喜歡的網(wǎng)站

    • 2931785位工程師會(huì)員交流學(xué)習(xí)
    • 獲取您個(gè)性化的科技前沿技術(shù)信息
    • 參加活動(dòng)獲取豐厚的禮品