亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Go語(yǔ)言編譯原理之變量捕獲

 更新時(shí)間:2022年08月04日 15:06:26   作者:書(shū)旅  
這篇文章主要為大家介紹了Go語(yǔ)言編譯原理之變量捕獲示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

前言

在前邊的幾篇文章中已經(jīng)基本分享完了編譯器前端的一些工作,后邊的幾篇主要是關(guān)于編譯器對(duì)抽象語(yǔ)法樹(shù)進(jìn)行分析和重構(gòu),然后完成一系列的優(yōu)化,其中包括以下五個(gè)部分:

  • 變量捕獲
  • 函數(shù)內(nèi)聯(lián)
  • 逃逸分析
  • 閉包重寫(xiě)
  • 遍歷函數(shù)

后邊的五篇文章主要就是上邊這五個(gè)主題,本文分享的是變量捕獲,變量捕獲主要是針對(duì)閉包場(chǎng)景的,因?yàn)殚]包函數(shù)中可能引用閉包外的變量,因此變量捕獲需要明確在閉包中通過(guò)值引用或地址引用的方式來(lái)捕獲變量

變量捕獲概述

下邊通過(guò)一個(gè)示例來(lái)看一下什么是變量捕獲

package main
import (
	"fmt"
)
func main() {
	a := 1
	b := 2
	go func() {
		//在閉包里對(duì)a或b進(jìn)行了重新賦值,也會(huì)改變引用方式
		fmt.Println(a, b)
	}()
	a = 666
}

我們可以看到在閉包中引用了外部的變量a、b,由于變量a在閉包之后進(jìn)行了其他賦值操作,因此在閉包中,a、b變量的引用方式會(huì)有所不同。在閉包中,必須采取地址引用的方式對(duì)變量a進(jìn)行操作,而對(duì)變量b的引用將通過(guò)直接值傳遞的方式進(jìn)行

我們可以通過(guò)如下方式查看當(dāng)前程序閉包變量捕獲的情況

go tool compile -m=2 main.go | grep capturing

assign=true代表變量a在閉包完成后又進(jìn)行了賦值操作

也可以看一個(gè)稍微復(fù)雜的

func adder() func(int) int {//累加器
	sum := 0 //地址引用
	return func(v int) int {
		sum += v
		return sum
	}
}
func main() {
	a := adder()
	for i:=0;i<10;i++{
		fmt.Printf("0 + 1 + ... + %d = %d\n", i, a(i))
	}
}

上一篇文章分享了類型檢查,我們可以繼續(xù)順著編譯的入口文件中類型檢查后邊的代碼往下看,你會(huì)看到如下這段代碼

編譯入口文件:src/cmd/compile/main.go -> gc.Main(archInit)
// Phase 4: Decide how to capture closed variables.(決定如何捕獲閉包變量)
// This needs to run before escape analysis,
// because variables captured by value do not escape.(變量捕獲應(yīng)該在逃逸分析之前進(jìn)行,因?yàn)橹殿愋偷淖兞坎东@,不會(huì)進(jìn)行逃逸分析)
	timings.Start("fe", "capturevars")
	for _, n := range xtop {
		if n.Op == ODCLFUNC && n.Func.Closure != nil { //函數(shù)需要是閉包類型
			Curfn = n
			capturevars(n)
		}
	}
	capturevarscomplete = true

從上邊這段代碼及注釋中,我們可以得到以下幾個(gè)信息:

  • 變量捕獲應(yīng)該在逃逸分析之前進(jìn)行,因?yàn)橹殿愋偷淖兞坎东@,不會(huì)進(jìn)行逃逸分析
  • 變量捕獲是針對(duì)閉包函數(shù)的
  • 變量捕獲的實(shí)現(xiàn)主要是調(diào)用了:src/cmd/compile/internal/gc/closure.go→capturevars

下邊我們就去看capturevars方法的內(nèi)部實(shí)現(xiàn),了解變量捕獲的一些細(xì)節(jié)

變量捕獲底層實(shí)現(xiàn)

所有類型檢查完成后,capturevars將在單獨(dú)的階段調(diào)用,它決定閉包捕獲的每個(gè)變量是通過(guò)值還是通過(guò)引用捕獲

func capturevars(xfunc *Node) {
	......
	clo := xfunc.Func.Closure
	cvars := xfunc.Func.Cvars.Slice()
	out := cvars[:0]
	for _, v := range cvars {
		......
		out = append(out, v)
		......
		outer := v.Name.Param.Outer
		outermost := v.Name.Defn
		// out parameters will be assigned to implicitly upon return.
		if outermost.Class() != PPARAMOUT && !outermost.Name.Addrtaken() && !outermost.Name.Assigned() && v.Type.Width <= 128 {
			v.Name.SetByval(true)
		} else {
			outermost.Name.SetAddrtaken(true)
			outer = nod(OADDR, outer, nil)
		}
		......
		outer = typecheck(outer, ctxExpr)
		clo.Func.Enter.Append(outer)
	}
	xfunc.Func.Cvars.Set(out)
	lineno = lno
}

該方法的代碼量很少,大致內(nèi)容就是,它會(huì)先獲取到閉包函數(shù)內(nèi)所有變量節(jié)點(diǎn),然后對(duì)這些節(jié)點(diǎn)進(jìn)行遍歷。確定該閉包需要捕獲的變量之后再?zèng)]有被修改時(shí),該變量小于128字節(jié),則會(huì)認(rèn)為他是值引用。后邊它會(huì)對(duì)外部引用的結(jié)點(diǎn)進(jìn)行類型檢查

總結(jié)

本部分比較簡(jiǎn)單,但是挺實(shí)用的,特別是我這種一直搞不明包閉包引用外部變量的人。后邊的逃逸分析、閉包重寫(xiě)跟變量捕獲有一定的聯(lián)系,介紹的后邊內(nèi)容的時(shí)候再提

以上就是Go語(yǔ)言編譯原理之變量捕獲的詳細(xì)內(nèi)容,更多關(guān)于Go編譯原理變量捕獲的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Golang?RPC的原理與簡(jiǎn)單調(diào)用詳解

    Golang?RPC的原理與簡(jiǎn)單調(diào)用詳解

    RPC(Remote?Procedure?Call),主要是幫助我們屏蔽網(wǎng)絡(luò)編程細(xì)節(jié)?,使我們更專注于業(yè)務(wù)邏輯,所以本文主要來(lái)和大家聊聊RPC的原理與簡(jiǎn)單調(diào)用,希望對(duì)大家有所幫助
    2023-05-05
  • Go讀寫(xiě)鎖操作方法示例詳解

    Go讀寫(xiě)鎖操作方法示例詳解

    這篇文章主要為大家介紹了Go讀寫(xiě)鎖方法示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-07-07
  • golang實(shí)現(xiàn)實(shí)時(shí)監(jiān)聽(tīng)文件并自動(dòng)切換目錄

    golang實(shí)現(xiàn)實(shí)時(shí)監(jiān)聽(tīng)文件并自動(dòng)切換目錄

    這篇文章主要給大家介紹了golang實(shí)現(xiàn)實(shí)時(shí)監(jiān)聽(tīng)文件,并自動(dòng)切換目錄,文中通過(guò)代碼示例給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作有一定的參考價(jià)值,需要的朋友可以參考下
    2023-12-12
  • goland 恢復(fù)已更改文件的操作

    goland 恢復(fù)已更改文件的操作

    這篇文章主要介紹了goland 恢復(fù)已更改文件的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2021-04-04
  • go mock模擬接口的實(shí)現(xiàn)

    go mock模擬接口的實(shí)現(xiàn)

    本文主要介紹了go mock模擬接口的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2023-06-06
  • Go語(yǔ)言HTTP請(qǐng)求流式寫(xiě)入body的示例代碼

    Go語(yǔ)言HTTP請(qǐng)求流式寫(xiě)入body的示例代碼

    這篇文章主要介紹了Go語(yǔ)言HTTP請(qǐng)求流式寫(xiě)入body,本文通過(guò)示例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-06-06
  • Golang切片連接成字符串的實(shí)現(xiàn)示例

    Golang切片連接成字符串的實(shí)現(xiàn)示例

    本文主要介紹了Golang切片連接成字符串的實(shí)現(xiàn)示例,可以使用Go語(yǔ)言中的內(nèi)置函數(shù)"String()"可以將字節(jié)切片轉(zhuǎn)換為字符串,具有一定的參考價(jià)值,感興趣的可以了解一下
    2023-11-11
  • Go?1.21新內(nèi)置函數(shù)min、max和clear的用法詳解

    Go?1.21新內(nèi)置函數(shù)min、max和clear的用法詳解

    Go?1.21?版本已經(jīng)正式發(fā)布,它帶來(lái)了許多新特性和改進(jìn),其中引入了的三個(gè)新內(nèi)置函數(shù):max、min?和?clear,接下來(lái)我們就來(lái)看看這些函數(shù)的用途和特點(diǎn)吧
    2023-08-08
  • graphql---go http請(qǐng)求使用詳解

    graphql---go http請(qǐng)求使用詳解

    這篇文章主要介紹了graphql---go http請(qǐng)求使用詳解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2020-12-12
  • Golang遞歸獲取目錄下所有文件方法實(shí)例

    Golang遞歸獲取目錄下所有文件方法實(shí)例

    這篇文章主要給大家介紹了關(guān)于Golang遞歸獲取目錄下所有文件的相關(guān)資料,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2023-02-02

最新評(píng)論