精品国产人成在线_亚洲高清无码在线观看_国产在线视频国产永久2021_国产AV综合第一页一个的一区免费影院黑人_最近中文字幕MV高清在线视频

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

詳細介紹go語言中的閉包的實現

馬哥Linux運維 ? 來源:tiancaiamao ? 作者:tiancaiamao ? 2021-10-20 16:18 ? 次閱讀

什么是閉包?什么場景下會用閉包
本文對go 語言中的閉包做了詳細介紹。

閉包是由函數及其相關引用環境組合而成的實體(即:閉包=函數+引用環境)。

Go中的閉包

閉包是函數式語言中的概念,沒有研究過函數式語言的用戶可能很難理解閉包的強大,相關的概念超出了本書的范圍。Go語言是支持閉包的,這里只是簡單地講一下在Go語言中閉包是如何實現的。

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

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

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

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

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

escape analyze

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

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

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

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

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

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

gobuild--gcflags=-mmain.go

可以看到輸出:

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

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

閉包結構體

回到閉包的實現來,前面說過,閉包是函數和它所引用的環境。那么是不是可以表示為一個結構體呢:

typeClosurestruct{
Ffunc()()
i*int
}

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

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)//這個結構體就是閉包的類型
...
CALL,runtime.new(SB)//接下來相當于new(Closure)
PCDATA$0,$-1
MOVQ8(SP),AX
NOP,
MOVQ$"".func·001+0(SB),BP
MOVQBP,(AX)//函數地址賦值給Closure的F部分
NOP,
MOVQ"".&i+16(SP),BP//將堆中new的變量i的地址賦值給Closure的值部分
MOVQBP,8(AX)
MOVQAX,"".~r1+40(FP)
ADDQ$24,SP
RET,

其中func·001是另一個函數的函數地址,也就是f返回的那個函數。

小結

  1. Go語言支持閉包
  2. Go語言能通過escape analyze識別出變量的作用域,自動將變量在堆上分配。將閉包環境變量在堆上分配是Go實現閉包的基礎。
  3. 返回閉包時并不是單純返回一個函數,而是返回了一個結構體,記錄下函數返回地址和引用的環境中的變量地址。

轉自:

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

編輯:jq
聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • C語言
    +關注

    關注

    180

    文章

    7601

    瀏覽量

    136251
  • 函數
    +關注

    關注

    3

    文章

    4308

    瀏覽量

    62444
  • 代碼
    +關注

    關注

    30

    文章

    4753

    瀏覽量

    68368
  • go語言
    +關注

    關注

    1

    文章

    158

    瀏覽量

    9032

原文標題:Golang 閉包的實現

文章出處:【微信號:magedu-Linux,微信公眾號:馬哥Linux運維】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏

    評論

    相關推薦

    在學習go語言的過程踩過的坑

    作為一個5年的phper,這兩年公司和個人都在順應技術趨勢,新項目慢慢從php轉向了go語言,從2021年到現在,筆者手上也先后開發了兩個go項目。在學習go
    的頭像 發表于 11-11 09:22 ?114次閱讀

    C語言中的socket編程基礎

    Socket編程簡介 Socket是一種通信機制,允許程序之間進行通信。在C語言中,socket編程是網絡編程的基礎。通過使用socket,程序可以發送和接收數據,實現不同計算機之間的通信
    的頭像 發表于 11-01 16:51 ?248次閱讀

    go語言如何解決并發問題

    作為一個后端開發,日常工作中接觸最多的兩門語言就是PHP和GO了。無可否認,PHP確實是最好的語言(手動狗頭哈哈),寫起來真的很舒爽,沒有任何心智負擔,字符串和整型壓根就不用區分,開發速度真的是比
    的頭像 發表于 10-23 13:38 ?113次閱讀
    <b class='flag-5'>go</b><b class='flag-5'>語言</b>如何解決并發問題

    c語言中從左到右結合怎么看

    在C語言中,操作符的結合性(Associativity)是指當操作符在表達式中連續出現時,它們如何與操作數結合的順序。對于大多數二元操作符(即需要兩個操作數的操作符),C語言遵循兩種基本的結合方式
    的頭像 發表于 08-20 11:42 ?724次閱讀

    三十分鐘入門基礎Go Java小子版

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

    小型繼電器的常開常點是什么

    小型繼電器是一種常見的電子元件,廣泛應用于自動控制、電力系統、通信設備等領域。在繼電器的工作原理中,常開常點是其核心組成部分,對于繼電器的正常工作至關重要。本文將詳細介紹小型繼電器的常開常
    的頭像 發表于 06-29 10:20 ?670次閱讀

    Go語言中的函數、方法與接口詳解

    Go 沒有類,不過可以為結構體類型定義方法。方法就是一類帶特殊的接收者參數的函數。方法接收者在它自己的參數列表內,位于 func 關鍵字和方法名之間。(非結構體類型也可以定義方法)
    的頭像 發表于 04-23 16:21 ?756次閱讀

    介紹C語言中錯誤處理和異常處理的一些常用的方法和策略

    C語言是一種低級的、靜態的、結構化的編程語言,它沒有提供像C++或Java等高級語言中的異常處理機制,例如try-catch-finally等。
    的頭像 發表于 02-28 14:25 ?591次閱讀

    如何解決C語言中的“訪問權限沖突”異常?C語言引發異常原因分析

    一些措施來解決和防止其發生。本文將詳細介紹C語言中訪問權限沖突異常的原因以及解決方法。 一、訪問權限沖突異常的原因分析 訪問權限沖突異常可分為兩類:訪問私有成員和訪問未定義成員。下面分別分析這兩種異常的原因。 1. 訪問
    的頭像 發表于 01-12 16:03 ?5192次閱讀

    C語言中結構體能不能相加

    C語言中,結構體能不能相加?
    的頭像 發表于 12-19 17:04 ?1221次閱讀
    C<b class='flag-5'>語言中</b>結構體能不能相加

    使用go語言實現一個grpc攔截器

    在開發grpc服務時,我們經常會遇到一些通用的需求,比如:日志、鏈路追蹤、鑒權等。這些需求可以通過grpc攔截器來實現。本文使用go語言實現一個 grpc一元模式(Unary)攔截器
    的頭像 發表于 12-18 10:13 ?638次閱讀
    使用<b class='flag-5'>go</b><b class='flag-5'>語言實現</b>一個grpc攔截器

    Go編程語言-你應該知道的一切

    Go 編程語言的故事始于 Google,當時三位工程師 Robert Griesemer、Rob Pike 和 Ken Thompson 對 C++ 的復雜性以及缺乏提供高效編譯和執行的簡單語言感到厭倦。
    的頭像 發表于 12-11 17:37 ?620次閱讀

    c語言中邏輯真等價于什么

    在C語言中,邏輯真等價于1。邏輯真可以理解為一個表達式、語句或條件的結果為真,即滿足條件。在計算機科學和編程中,邏輯真在控制流語句、循環和條件語句中具有重要的作用。 邏輯真等價于條件為真的情況。在C
    的頭像 發表于 11-30 14:10 ?2027次閱讀

    c語言中數據溢出是歸0還是歸1

    在C語言中,數據溢出通常不會自動歸0或歸1,而是發生未定義行為。這是因為C語言中的數據類型都有一定范圍,超出該范圍的值會導致數據溢出。數據溢出意味著存儲在變量中的值超過了變量所能容納的最大值。 C
    的頭像 發表于 11-30 11:47 ?2626次閱讀

    c語言中decimal的含義

    C語言中的“decimal”是一種數據類型,用于表示十進制數字。在C語言中,常用的數據類型有整數類型(int)、浮點類型(float和double)、字符類型(char)等,而decimal則是一種
    的頭像 發表于 11-30 10:57 ?2317次閱讀