最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Go語言表達(dá)式的求值順序

 更新時(shí)間:2026年06月05日 09:38:45   作者:念何架構(gòu)之路  
本文詳細(xì)講解了Go語言中的變量求值順序規(guī)則,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

1.包級別變量聲明語句表達(dá)式求值順序:

在一個(gè)Go包內(nèi)部.包級別變量聲明語句的表達(dá)式求值順序是由初始化依賴規(guī)則決定的.如下.

1).在Go包中.包級別變量的初始化按照變量聲明的先后順序進(jìn)行.

2).如果某個(gè)變量(如變量a)的初始化表達(dá)式中直接或間接依賴其他變量(如變量b).那么變量a的初始化順序排在變量b后面.

3).未初始化的且不含有對應(yīng)初始化表達(dá)式或初始化表達(dá)式不依賴任何未初始化變量的變量.稱之為ready for initialization變量.

4).包級別變量的初始化是逐步進(jìn)行的.每一步就是按照變量聲明順序找到下一個(gè)"ready for initialization"變量并對其進(jìn)行初始化的過程.反復(fù)重復(fù)這一步驟.直到?jīng)]有ready for inititlization變量為止.

5).位于同一包內(nèi)但不同文件中的變量的聲明順序依賴編譯器處理文件順序.先處理的文件中的變量聲明順序先于后處理的文件中的所有變量.

示例:

var (
    a = c + b
    b = f()
    c = f()
    d = 3
)

func f() int {
    d++
    return d
}
func main() {
    fmt.Println(a, b, c, d)
}

1).根據(jù)規(guī)則.包集變量初始化按照變量聲明先后順序進(jìn)行.因此每一輪尋找"ready for initialization"變量過程都會(huì)按照a->b->c->d的順序依次進(jìn)行.

2).先來進(jìn)行第一輪選擇"ready for initialization"變量過程.從變量a開始.變量a的初始化表達(dá)式為c+b.這使得a的初始化依賴b+c.而b+c通過函數(shù)f間接依賴未初始化變量d.因此a并不是"ready for initialization"變量.

3).按聲明順序.接下來是b.b的初始化表達(dá)式依賴函數(shù)f.而函數(shù)f依賴未初始化未初始化變量d.因此b也不是"ready for initialization".

4).按照聲明順序.接下來是c.c的初始化表達(dá)式依賴函數(shù)f.而函數(shù)f依賴未初始化變量d.因此c也不是"ready for initialization".

5).接下來是d.d沒有需求值的初始化表達(dá)式.而是直接賦予了初值.因此d就是第一輪尋找的"ready for initialization".對其進(jìn)行初始化d=3.

6).接下來第二輪尋找.依然從a開始.和第一輪一樣.b c依舊是未初始化變量.a不滿足條件.b依賴函數(shù)f.函數(shù)f依賴d.但d已經(jīng)是初始化變量集合中的元素了.b具備了成為"ready for initialization"的條件.于是第二輪對b進(jìn)行了初始化.b=3+1=4.

7).第三輪尋找.和前兩輪一樣.c依舊是未初始化變量.a不符合條件.c依賴函數(shù)f.函數(shù)f依賴d.d已經(jīng)是已初始化變量集合中的元素了.c具備了條件.對c進(jìn)行初始化c=4+1=5.

8).進(jìn)行最后一輪尋找.b和c都已經(jīng)初始化完成了.所以a=5+4=9.

9).初始化結(jié)束.根據(jù)上述分析.程序應(yīng)該輸出 9 4 5 5.

執(zhí)行結(jié)果:

如果在包級變量中使用了變量_.空變量也會(huì)得到Go編譯器一視同仁的對待.

示例:

var (
    a = c + b
    b = f()
    _ = f()
    c = f()
    d = 3
)

func f() int {
    d++
    return d
}
func main() {
    fmt.Println(a, b, c, d)
}

1).初始化過程按照a->b->_->c->d的順序進(jìn)行"ready for initialization"變量查找.

2).第一輪:變量a b _ c都不符合條件.d被選出初始化.d=3.

3).第二輪:變量b符合條件被篩選出并初始化.d=4 b=4

4).第三輪:空變量符合條件被篩選出初始化.空變量忽略了初始值.這一過程的副作用是使得變量d增加1.d=5,b=4.

5).第四輪:變量c符合條件被篩選出初始化.d=6,b=4,c=6.

6).第五輪:變量a符合條件被選出并初始化.d=6,b=4,c=6,a=10

7).包變量初始化結(jié)束.分析輸出結(jié)果.10 4 6 6.

執(zhí)行結(jié)果:

多個(gè)變量在聲明語句左側(cè)且右側(cè)為單一表達(dá)式時(shí)的求值情況.這種情況下.無論左側(cè)哪個(gè)變量被初始化.同一行的其他變量也會(huì)被一并初始化.

示例:

var (
    a    = c 
    b, c = f()
    d    = 3
)

func f() (int, int) {
    return d, d + 1
}
func main() {
    fmt.Println(a, b, c, d)
}

1).根據(jù)包級變量的初始化規(guī)則.初始化過程a->b&c->d順序進(jìn)行"ready for initialization"變量查找.

2).第一輪:變量 a b c都不符合條件.d被選出初始化.d=3.

3).第二輪.變量b和c一起符合條件.以b被選出為例.b的初始化同時(shí).c也得到初始化.b=3,c=4,d=4.

4).第三輪:變量a符合條件被選出并初始化.d=4,b=3,c=4,a=3.

5).包變量初始化結(jié)束.分析輸出結(jié)果為4 3 4 3.

執(zhí)行結(jié)果:

2.普通求值順序:

除了包級變量由初始化依賴決定求值順序.Go語言還定義了普通求值順序.用于規(guī)定表達(dá)式操作數(shù)中的函數(shù) 方法 以及channel的操作求值順序.Go規(guī)定表達(dá)式操作數(shù)中的所有函數(shù) 方法以及channel操作按照從左到右的次序依次進(jìn)行求值.

示例:

func f() int {
    fmt.Println("calling f")
    return 1
}

func g(a, b, c int) int {
    fmt.Println("calling g")
    return 2
}

func h() int {
    fmt.Println("calling h")
    return 3
}

func i() int {
    fmt.Println("calling i")
    return 1
}

func j() int {
    fmt.Println("calling j")
    return 1
}

func k() bool {
    fmt.Println("calling k")
    return true
}

func main() {
    var y = []int{11, 12, 13}
    var x = []int{21, 22, 23}

    var c chan int = make(chan int)
    go func() {
       c <- 1
    }()

    y[f()], _ = g(h(), i()+x[j()], <-c), k()
}

1).按照從左到右的順序.先對等號左側(cè)表達(dá)式操作數(shù)中的函數(shù)進(jìn)行調(diào)用值.因此第一個(gè)是y[f()]中的f().

2).接下來是等號右側(cè)的表達(dá)式.第一個(gè)函數(shù)是g().但g()依賴其參數(shù)的求值.其參數(shù)列表依然可以看成是一個(gè)多賦值操作.其涉及的函數(shù)調(diào)用順序從左到右依次為h() i() j() <-c.這樣該表達(dá)式的求值順序即為h()->i()->j()->c取值操作->g().

3).最后還剩下末尾的k(),因此該語句中函數(shù)以及channel操作的完整求值順序是.f()->h()->i()->j()->c取值操作->g()->k().

執(zhí)行結(jié)果:

當(dāng)普通求值順序與包級變量的初始化順序一并使用時(shí).后者優(yōu)先級更高.但每個(gè)單獨(dú)表達(dá)式中的操作數(shù)求值依舊按照普通求值順序的規(guī)則.

示例:

var a, b, c = f() + v(), g(), sqr(u()) + v()

func f() int {
    fmt.Println("calling f")
    return c
}

func g() int {
    fmt.Println("calling g")
    return 1
}

func sqr(x int) int {
    fmt.Println("calling sqr")
    return x * x
}

func v() int {
    fmt.Println("calling v")
    return 1
}

func u() int {
    fmt.Println("calling u")
    return 2
}

func main() {
    fmt.Println(a, b, c)
}

根據(jù)包變量初始化依賴規(guī)則以及普通求值順序規(guī)則對這個(gè)例子進(jìn)行簡要分析.把單行的聲明語句等價(jià)轉(zhuǎn)換為下面的代碼.這樣看起來更直觀.(注意:與前面多個(gè)變量在聲明語句左側(cè)且右側(cè)為單一表達(dá)式時(shí)的表達(dá)式求值情況不同.這里右側(cè)并非單一表達(dá)式).

var (
    a = f() + v()
    b = g()
    c = sqr(u()) + v()
)

1).根據(jù)包變量初始化規(guī)則.初始化過程按照"a->b->c"順序進(jìn)行"ready for initialization"變量查找.

2).第一輪:變量a依賴c.b符合條件.b被初始化依賴普通求值順序規(guī)則.g被調(diào)用.

3).第二輪:變量c符合條件.c被選出初始化.依據(jù)普通求值順序規(guī)則,u sqr v先后被調(diào)用.

4).第三輪:變量a符合條件.a被選出初始化.依據(jù)普通求值順序規(guī)則.f v先后被調(diào)用.

5).綜合以上分析.得出調(diào)用順序:g->u->sqr->v->f->v.

執(zhí)行結(jié)果:

3.賦值語句求值:

n0 , n1 = n0 + n1 , n0

//或者 

n0 , n1 = op( n0 , n1), n0

這是一個(gè)賦值語句.Go語言規(guī)定.賦值語句求值分為兩個(gè)階段.

1).第一階段.對于等號左邊的下標(biāo)表達(dá)式 指針解引用表達(dá)式和符號右邊表達(dá)式中的操作數(shù).按照普通求值規(guī)則從左到右求值.

2).第二階段.按從左到右的順序?qū)ψ兞窟M(jìn)行賦值.

根據(jù)上述規(guī)則.對這個(gè)問題等號兩端的表達(dá)式的操作數(shù)采用從左到右的求值順序.

假定n0和n1的初始值如下.

n0 , n1 = 1 , 2

1).第一階段:等號兩端表達(dá)式求值.上述問題中.等號左邊沒有需要求值的下標(biāo)表達(dá)式 指針解引用表達(dá)式等.只有右端有

n0 + n1 和 n0兩個(gè)表達(dá)式.但表達(dá)式的操作數(shù)(n0 , n1)都是已初始化的.因此直接將值代入.得到求值結(jié)果.求值后.語句可以看成n0,n1=3,1.

2).第二階段.從左到右賦值.即n0=3,n1=1.

示例:

func example() {
    n0, n1 := 1, 2
    n0, n1 = n0+n1, n0
    fmt.Println(n0, n1)
}

func main() {
    example()
}

執(zhí)行結(jié)果:

4.switch/select語句中的表達(dá)式求值:

先看switch-case語句中的表達(dá)式求值.這類求值屬于"惰性求值"范疇.惰性求值指的就是進(jìn)行求值時(shí)才會(huì)對表達(dá)式進(jìn)行求值.這樣做的目的是讓計(jì)算機(jī)少做事.從而降低對程序的消耗.對性能提升有一定的幫助.

示例:

func expr(n int) int {
    fmt.Println(n)
    return n
}

func main() {
    switch expr(2) {
    case expr(1), expr(2), expr(3):
       fmt.Println("enter into case1")
       fallthrough
    case expr(4):
       fmt.Println("enter into case2")
    }
}

1).對于switch-case語句而言.首先進(jìn)行求值的是switch后面的表達(dá)式expr(2).這個(gè)表達(dá)式求值時(shí)輸出2.

2).接下來將按照從上到下 從左到右的順序?qū)ase語句中的表達(dá)式進(jìn)行求值.如果某個(gè)表達(dá)式的結(jié)果與switch表達(dá)式結(jié)果一致.那么求值停止.后面未求值的case表達(dá)式將被忽略.

3).fallthrough將執(zhí)行權(quán)直接轉(zhuǎn)移到下一個(gè)case執(zhí)行語句中.略過了case表達(dá)式expr(4)的求值.

執(zhí)行結(jié)果:

Go語言中的select語句為我們提供了一種在多個(gè)channel間實(shí)現(xiàn)多路復(fù)用的機(jī)制.是編寫Go并發(fā)程序最常見的語句之一.

示例:

func getAReadOnlyChannel() <-chan int {
    fmt.Println("invoke getAReadOnlyChannel")
    c := make(chan int)

    go func() {
       time.Sleep(3 * time.Second)
       c <- 1
    }()
    return c
}

func getASlice() *[5]int {
    fmt.Println("invoke getASlice")
    var a [5]int
    return &a
}

func getAWriteChannel() chan<- int {
    fmt.Println("invoke getAWriteChannel")
    return make(chan int)
}

func getANumToChannel() int {
    fmt.Println("invoke getANumToChannel")
    return 2
}

func main() {
    select {
    //從channel接收數(shù)據(jù)
    case (getASlice())[0] = <-getAReadOnlyChannel():
       fmt.Println("recv something from a readonly channel")
    case getAWriteChannel() <- getANumToChannel():
       fmt.Println("send something to a writeonly channel")
    }
}

1).select在執(zhí)行的時(shí)候.首先所有case表達(dá)式都會(huì)按出現(xiàn)的先后順序求值一遍.

有一個(gè)例外.位于case等號左邊的從channel接收數(shù)據(jù)的表達(dá)式(RecvStmt)不會(huì)被求值.這里對應(yīng)的是getASilce.

2).如果選擇要執(zhí)行的是一個(gè)從channel接收數(shù)據(jù)的case.那么該case等號左邊的表達(dá)式在接收前才會(huì)被求值.上面的例子中.在getAReadOnlyChannel創(chuàng)建的goroutine在3s后向channel中寫入一個(gè)int值后.select選擇了第一個(gè)case執(zhí)行.此時(shí)對等號左側(cè)的表達(dá)式(getASlice())[0]進(jìn)行求值.輸出"invoke getASlice".也算是一種惰性求值.

執(zhí)行結(jié)果:

到此這篇關(guān)于Go語言表達(dá)式的求值順序的文章就介紹到這了,更多相關(guān)Go語言表達(dá)式求值順序內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 分析Go語言接口的設(shè)計(jì)原則

    分析Go語言接口的設(shè)計(jì)原則

    interface是Go語言的基礎(chǔ)特性之一, 可以理解為對一種類型的規(guī)范或者約束。他跟java、c++不同, Go語言實(shí)現(xiàn)接口不需要顯示說明實(shí)現(xiàn)了哪個(gè)接口, 也沒有繼承或者子類或者implement關(guān)鍵字。只是通過約定的形式, 隱式的實(shí)現(xiàn)接口中的方法即可
    2021-06-06
  • Go語言使用Etcd實(shí)現(xiàn)分布式鎖

    Go語言使用Etcd實(shí)現(xiàn)分布式鎖

    etcd是近幾年比較火熱的一個(gè)開源的、分布式的鍵值對數(shù)據(jù)存儲系統(tǒng),本文將介紹如何利用Etcd實(shí)現(xiàn)分布式鎖,感興趣的小伙伴可以跟隨小編一起了解一下
    2023-05-05
  • Golang實(shí)現(xiàn)請求限流的幾種辦法(小結(jié))

    Golang實(shí)現(xiàn)請求限流的幾種辦法(小結(jié))

    這篇文章主要介紹了Golang實(shí)現(xiàn)請求限流的幾種辦法(小結(jié)),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-10-10
  • Go開發(fā)Gin項(xiàng)目添加jwt功能實(shí)例詳解

    Go開發(fā)Gin項(xiàng)目添加jwt功能實(shí)例詳解

    這篇文章主要為大家介紹了Go開發(fā)Gin項(xiàng)目中添加jwt功能實(shí)例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-07-07
  • Golang常用的幾種密碼加密方式分享

    Golang常用的幾種密碼加密方式分享

    這篇文章給大家介紹了Golang常用的幾種密碼加密方式,加密有兩種方式,一種是直接加密,一種是鹽值加密,直接加密指的是將原始密碼直接進(jìn)行加密,鹽值加密則是在進(jìn)行密碼加密之前,文中有詳細(xì)的代碼示例,需要的朋友可以參考下
    2023-08-08
  • Go語言使用AES加密解密的示例代碼

    Go語言使用AES加密解密的示例代碼

    這篇文章主要介紹了Go語言使用AES加密解密的示例代碼,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-09-09
  • Go語言基礎(chǔ)map用法及示例詳解

    Go語言基礎(chǔ)map用法及示例詳解

    這篇文章主要為大家介紹了Go語言基礎(chǔ)map的用法及示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2021-11-11
  • Go語言七篇入門教程七GC垃圾回收三色標(biāo)記

    Go語言七篇入門教程七GC垃圾回收三色標(biāo)記

    這篇文章主要為大家介紹了Go語言教程關(guān)于GC垃圾回收三色標(biāo)記的示例詳解,本篇文章是Go語言七篇入門教程系列文章,有需要的朋友可以借鑒參考下,希望能夠有所幫助
    2021-11-11
  • 一文帶你熟悉Go語言中的分支結(jié)構(gòu)

    一文帶你熟悉Go語言中的分支結(jié)構(gòu)

    這篇文章主要和大家分享一下Go語言中的分支結(jié)構(gòu)(if?-?else-if?-?else、switch),文中的示例代碼講解詳細(xì),對我們學(xué)習(xí)Go語言有一定的幫助,需要的可以參考一下
    2022-11-11
  • Go語言基礎(chǔ)學(xué)習(xí)之?dāng)?shù)組的使用詳解

    Go語言基礎(chǔ)學(xué)習(xí)之?dāng)?shù)組的使用詳解

    數(shù)組相必大家都很熟悉,各大語言也都有數(shù)組的身影。Go 語言也提供了數(shù)組類型的數(shù)據(jù)結(jié)構(gòu)。本文就來通過一些簡單的示例帶大家了解一下Go語言中數(shù)組的使用,希望對大家有所幫助
    2022-12-12

最新評論

凌云县| 怀远县| 安图县| 弥勒县| 襄樊市| 绥宁县| 原阳县| 富蕴县| 中卫市| 苍山县| 乡宁县| 威海市| 商洛市| 辽宁省| 牡丹江市| 灵寿县| 资溪县| 满城县| 庆元县| 江西省| 儋州市| 平邑县| 潜江市| 平果县| 寿光市| 鹤岗市| 塘沽区| 岫岩| 桐乡市| 孙吴县| 永吉县| 玉门市| 龙州县| 泗洪县| 万盛区| 武鸣县| 新河县| 邵阳市| 图片| 荣成市| 师宗县|