欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

淺談golang package中init方法的多處定義及運(yùn)行順序問(wèn)題

 更新時(shí)間:2021年05月06日 10:49:55   作者:zhuxinquan61  
這篇文章主要介紹了淺談golang package中init方法的多處定義及運(yùn)行順序問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧

在不了解這個(gè)問(wèn)題之前,在網(wǎng)上搜索一下竟然搜出了兩個(gè)完全相反的結(jié)果,所以打算自己測(cè)試下這個(gè)問(wèn)題。

首先給出結(jié)論:

在同一個(gè)package中,可以多個(gè)文件中定義init方法

在同一個(gè)go文件中,可以重復(fù)定義init方法

在同一個(gè)package中,不同文件中的init方法的執(zhí)行按照文件名先后執(zhí)行各個(gè)文件中的init方法

在同一個(gè)文件中的多個(gè)init方法,按照在代碼中編寫(xiě)的順序依次執(zhí)行不同的init方法

下面看下測(cè)試的代碼:

在當(dāng)前目錄下新建main.go及testinit目錄,在testinit目錄下共有三個(gè)文件:123.go、ini1.go、ini2.go,各個(gè)源碼文件分別如下:

123.go

package testinit
import "fmt"
func init(){
    fmt.Println("123init")
}

ini1.go

package testinit
import "fmt"
func init(){
    fmt.Println("init1")
}
func init(){
    fmt.Println("init1-2")
}

ini2.go

package testinit
import "fmt"
func init(){
    fmt.Println("init2")
}

main.go

package main
import (
    _ "./testinit"
    "fmt"
)
func main(){
    fmt.Println("main")
}

如上main.go中導(dǎo)入testinit package,然后go build main.go,執(zhí)行顯示如下:

這里寫(xiě)圖片描述

從運(yùn)行的結(jié)構(gòu)就能很清晰的看到,123、ini1、ini2三個(gè)文件按照文件名執(zhí)行,對(duì)于ini1.go中的兩個(gè)ini方法按照init方法編寫(xiě)的先后順序執(zhí)行,最后才執(zhí)行的main方法!

補(bǔ)充:Golang中defer、return、返回值和main、init函數(shù)的陷阱

Go語(yǔ)言中延遲函數(shù)defer充當(dāng)著 cry...catch 的重任,使用起來(lái)也非常簡(jiǎn)便,然而在實(shí)際應(yīng)用中,很多gopher并沒(méi)有真正搞明白defer、return和返回值之間的執(zhí)行順序。他們的特點(diǎn):

多個(gè)defer的執(zhí)行順序?yàn)椤昂筮M(jìn)先出”;

defer、return、返回值三者的執(zhí)行邏輯應(yīng)該是:return最先執(zhí)行,return負(fù)責(zé)將結(jié)果寫(xiě)入返回值中;接著defer開(kāi)始執(zhí)行一些收尾工作;最后函數(shù)攜帶當(dāng)前返回值退出。

如何解釋兩種結(jié)果的不同:

上面兩段代碼的返回結(jié)果之所以不同,其實(shí)從上面第2條結(jié)論很好理解。

a()int 函數(shù)的返回值沒(méi)有被提前聲名,其值來(lái)自于其他變量的賦值,而defer中修改的也是其他變量,而非返回值本身,因此函數(shù)退出時(shí)返回值并沒(méi)有被改變。

b()(i int) 函數(shù)的返回值被提前聲名,也就意味著defer中是可以調(diào)用到真實(shí)返回值的,因此defer在return賦值返回值 i 之后,再一次地修改了 i 的值,最終函數(shù)退出后的返回值才會(huì)是defer修改過(guò)的值。

package main 
import (
 "fmt"
)
 
func main() { 
 fmt.Println("c return:", *(c())) // 打印結(jié)果為 c return: 2
 
}
 
func c() *int {
 var i int
 defer func() {
  i++
  fmt.Println("c defer2:", i) // 打印結(jié)果為 c defer: 2
 }()
 
 defer func() {
  i++
  fmt.Println("c defer1:", i) // 打印結(jié)果為 c defer: 1
 }()
 return &i
}

雖然 c()*int 的返回值沒(méi)有被提前聲明,但是由于 c()*int 的返回值是指針變量,那么在return將變量 i 的地址賦給返回值后,defer再次修改了 i 在內(nèi)存中的實(shí)際值,因此函數(shù)退出時(shí)返回值雖然依舊是原來(lái)的指針地址,但是其指向的內(nèi)存實(shí)際值已經(jīng)被成功修改了。

Go里面有兩個(gè)保留的函數(shù):init函數(shù)(能夠應(yīng)用于所有的package)和main函數(shù)(只能應(yīng)用于package main)。這兩個(gè)函數(shù)在定義時(shí)不能有任何的參數(shù)和返回值。雖然一個(gè)package里面可以寫(xiě)任意多個(gè)init函數(shù),但這無(wú)論是對(duì)于可讀性還是以后的可維護(hù)性來(lái)說(shuō),我們都強(qiáng)烈建議用戶在一個(gè)package中每個(gè)文件只寫(xiě)一個(gè)init函數(shù)。

Go程序會(huì)自動(dòng)調(diào)用init()和main(),所以你不需要在任何地方調(diào)用這兩個(gè)函數(shù)。每個(gè)package中的init函數(shù)都是可選的,但package main就必須包含一個(gè)main函數(shù)。

程序的初始化和執(zhí)行都起始于main包。如果main包還導(dǎo)入了其它的包,那么就會(huì)在編譯時(shí)將它們依次導(dǎo)入。有時(shí)一個(gè)包會(huì)被多個(gè)包同時(shí)導(dǎo)入,那么它只會(huì)被導(dǎo)入一次(例如很多包可能都會(huì)用到fmt包,但它只會(huì)被導(dǎo)入一次,因?yàn)闆](méi)有必要導(dǎo)入多次)。

當(dāng)一個(gè)包被導(dǎo)入時(shí),如果該包還導(dǎo)入了其它的包,那么會(huì)先將其它包導(dǎo)入進(jìn)來(lái),然后再對(duì)這些包中的包級(jí)常量和變量進(jìn)行初始化,接著執(zhí)行init函數(shù)(如果有的話),依次類推。

等所有被導(dǎo)入的包都加載完畢了,就會(huì)開(kāi)始對(duì)main包中的包級(jí)常量和變量進(jìn)行初始化,然后執(zhí)行main包中的init函數(shù)(如果存在的話),最后執(zhí)行main函數(shù)。

下圖詳細(xì)地解釋了整個(gè)執(zhí)行過(guò)程:

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教。

相關(guān)文章

  • Golang 使用接口實(shí)現(xiàn)泛型的方法示例

    Golang 使用接口實(shí)現(xiàn)泛型的方法示例

    這篇文章主要介紹了Golang 使用接口實(shí)現(xiàn)泛型的方法示例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-03-03
  • 詳解go中的defer鏈如何被遍歷執(zhí)行

    詳解go中的defer鏈如何被遍歷執(zhí)行

    為了在退出函數(shù)前執(zhí)行一些資源清理的操作,例如關(guān)閉文件、釋放連接、釋放鎖資源等,會(huì)在函數(shù)里寫(xiě)上多個(gè)defer語(yǔ)句,多個(gè)_defer 結(jié)構(gòu)體形成一個(gè)鏈表,G 結(jié)構(gòu)體中某個(gè)字段指向此鏈表,那么go中的defer鏈如何被遍歷執(zhí)行,本文將給大家詳細(xì)的介紹,感興趣的朋友可以參考下
    2024-01-01
  • Go Time庫(kù)中時(shí)間和日期相關(guān)的操作方法整理

    Go Time庫(kù)中時(shí)間和日期相關(guān)的操作方法整理

    這篇文章主要為大家整理了Go語(yǔ)言中的time庫(kù),包括時(shí)間、日期和時(shí)區(qū)等相關(guān)概念及使用方法,希望通過(guò)掌握這些知識(shí),大家可以更好地處理時(shí)間、日期和時(shí)區(qū)相關(guān)的問(wèn)題
    2023-08-08
  • Golang等多種語(yǔ)言轉(zhuǎn)數(shù)組成字符串舉例詳解

    Golang等多種語(yǔ)言轉(zhuǎn)數(shù)組成字符串舉例詳解

    今天寫(xiě)代碼遇到數(shù)組轉(zhuǎn)換成字符串操作,下面這篇文章主要給大家介紹了關(guān)于Golang等多種語(yǔ)言轉(zhuǎn)數(shù)組成字符串的相關(guān)資料,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2023-05-05
  • Go語(yǔ)言的GOPATH與工作目錄詳解

    Go語(yǔ)言的GOPATH與工作目錄詳解

    這篇文章主要介紹了Go語(yǔ)言的GOPATH與工作目錄詳解,本文詳細(xì)講解了GOPATH設(shè)置、應(yīng)用目錄結(jié)構(gòu)、編譯應(yīng)用等內(nèi)容,需要的朋友可以參考下
    2014-10-10
  • Go 并發(fā)讀寫(xiě) sync.map 詳細(xì)

    Go 并發(fā)讀寫(xiě) sync.map 詳細(xì)

    閱讀本文你將會(huì)明確 sync.Map 和原生 map +互斥鎖/讀寫(xiě)鎖之間的性能情況。標(biāo)準(zhǔn)庫(kù) sync.Map 雖說(shuō)支持并發(fā)讀寫(xiě) map,但更適用于讀多寫(xiě)少的場(chǎng)景,因?yàn)樗麑?xiě)入的性能比較差,使用時(shí)要考慮清楚這一點(diǎn)。
    2021-10-10
  • Golang校驗(yàn)字符串是否JSON格式的方法總結(jié)

    Golang校驗(yàn)字符串是否JSON格式的方法總結(jié)

    這篇文章主要為大家詳細(xì)介紹了Golang中校驗(yàn)字符串是否JSON格式的方法,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起了解一下
    2023-04-04
  • 在Golang中使用Redis的方法示例

    在Golang中使用Redis的方法示例

    這篇文章主要介紹了在Golang中使用Redis的方法示例,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-06-06
  • Go語(yǔ)言之init函數(shù)

    Go語(yǔ)言之init函數(shù)

    Go語(yǔ)言有一個(gè)特殊的函數(shù)init,先于main函數(shù)執(zhí)行,實(shí)現(xiàn)包級(jí)別的一些初始化操作。這篇文章介紹了Go中的Init函數(shù),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2022-07-07
  • Go語(yǔ)言實(shí)現(xiàn)23種設(shè)計(jì)模式的使用

    Go語(yǔ)言實(shí)現(xiàn)23種設(shè)計(jì)模式的使用

    設(shè)計(jì)模式是軟件工程中各種常見(jiàn)問(wèn)題的經(jīng)典解決方案,,本文主要介紹了Go語(yǔ)言實(shí)現(xiàn)23種設(shè)計(jì)模式的使用,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2022-05-05

最新評(píng)論