日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

神奇的 Go init 函数

發(fā)布時間:2024/4/11 编程问答 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 神奇的 Go init 函数 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

前言

哈嘍,兄弟們,我是asong。今天與大家聊一聊Go語言中的神奇函數(shù)init,為什么叫他神奇函數(shù)呢?因為該函數(shù)可以在所有程序執(zhí)行開始前被調(diào)用,并且每個包下可以有多個init函數(shù)。這個函數(shù)使用起來比較簡單,但是你們知道他的執(zhí)行順序是怎樣的嘛?本文我們就一起來解密。

init函數(shù)的特性

先簡單介紹一下init函數(shù)的基本特性:

  • init函數(shù)先于main函數(shù)自動執(zhí)行

  • 每個包中可以有多個init函數(shù),每個包中的源文件中也可以有多個init函數(shù)

  • init函數(shù)沒有輸入?yún)?shù)、返回值,也未聲明,所以無法引用

  • 不同包的init函數(shù)按照包導(dǎo)入的依賴關(guān)系決定執(zhí)行順序

  • 無論包被導(dǎo)入多少次,init函數(shù)只會被調(diào)用一次,也就是只執(zhí)行一次

init函數(shù)的執(zhí)行順序

我在剛學(xué)習(xí)init函數(shù)時就對他的執(zhí)行順序很好奇,在谷歌上搜了幾篇文章,他們都有一樣的圖:

下圖來源于網(wǎng)絡(luò):

截屏2021-06-05 上午9.55.15

這張圖片很清晰的反應(yīng)了init函數(shù)的加載順序:

  • 包加載優(yōu)先級排在第一位,先層層遞歸進行包加載

  • 每個包中加載順序為:const > var > init,首先進行初始化的是常量,然后是變量,最后才是init函數(shù)。針對包級別的變量初始化順序,Go官方文檔給出這樣一個例子:

var?(a?=?c?+?b??//?==?9b?=?f()????//?==?4c?=?f()????//?==?5d?=?3??????//?==?5?after?initialization?has?finished )func?f()?int?{d++return?d }

變量的初始化按出現(xiàn)的順序從前往后進行,假若某個變量需要依賴其他變量,則被依賴的變量先初始化。所以這個例子中,初始化順序是 d -> b -> c -> a。

上圖只是表達了init函數(shù)大概的加載順序,有些細節(jié)我們還是不知道的,比如:當前包下有多個init函數(shù),按照什么順序執(zhí)行,當前源文件下有多個init函數(shù),這又按照什么順序執(zhí)行呢?本來想寫個例子挨個驗證一下的,后來一看Go官方文檔中都有說明,也就沒有必要再寫一個例子啦,直接說結(jié)論吧:

  • 如果當前包下有多個init函數(shù),首先按照源文件名的字典序從前往后執(zhí)行。

  • 若一個文件中出現(xiàn)多個init函數(shù),則按照出現(xiàn)順序從前往后執(zhí)行。

前面說的有點亂,對init函數(shù)的加載順序做一個小結(jié):

從當前包開始,如果當前包包含多個依賴包,則先初始化依賴包,層層遞歸初始化各個包,在每一個包中,按照源文件的字典序從前往后執(zhí)行,每一個源文件中,優(yōu)先初始化常量、變量,最后初始化init函數(shù),當出現(xiàn)多個init函數(shù)時,則按照順序從前往后依次執(zhí)行,每一個包完成加載后,遞歸返回,最后在初始化當前包!

init函數(shù)的使用場景

還記得我之前的這篇文章嗎:go解鎖設(shè)計模式之單例模式,借用init函數(shù)的加載機制我們可以實現(xiàn)單例模式中的餓漢模式,具體怎么實現(xiàn)可以參考這篇文章,這里就不在寫一遍了。

init函數(shù)的使用場景還是挺多的,比如進行服務(wù)注冊、進行數(shù)據(jù)庫或各種中間件的初始化連接等。Go的標準庫中也有許多地方使用到了init函數(shù),比如我們經(jīng)常使用的pprof工具,他就使用到了init函數(shù),在init函數(shù)里面進行路由注冊:

//go/1.15.7/libexec/src/cmd/trace/pprof.go func?init()?{http.HandleFunc("/io",?serveSVGProfile(pprofByGoroutine(computePprofIO)))http.HandleFunc("/block",?serveSVGProfile(pprofByGoroutine(computePprofBlock)))http.HandleFunc("/syscall",?serveSVGProfile(pprofByGoroutine(computePprofSyscall)))http.HandleFunc("/sched",?serveSVGProfile(pprofByGoroutine(computePprofSched)))http.HandleFunc("/regionio",?serveSVGProfile(pprofByRegion(computePprofIO)))http.HandleFunc("/regionblock",?serveSVGProfile(pprofByRegion(computePprofBlock)))http.HandleFunc("/regionsyscall",?serveSVGProfile(pprofByRegion(computePprofSyscall)))http.HandleFunc("/regionsched",?serveSVGProfile(pprofByRegion(computePprofSched))) }

這里就不擴展太多了,更多標準庫中的使用方法大家可以自己去探索一下。

在這最后總結(jié)一下使用init要注意的問題吧:

  • 編程時不要依賴init的順序

  • 一個源文件下可以有多個init函數(shù),代碼比較長時可以考慮分多個init函數(shù)

  • 復(fù)雜邏輯不建議使用init函數(shù),會增加代碼的復(fù)雜性,可讀性也會下降

  • 在init函數(shù)中也可以啟動goroutine,也就是在初始化的同時啟動新的goroutine,這并不會影響初始化順序

  • init函數(shù)不應(yīng)該依賴任何在main函數(shù)里創(chuàng)建的變量,因為init函數(shù)的執(zhí)行是在main函數(shù)之前的

  • init函數(shù)在代碼中不能被顯示的調(diào)用,不能被引用(賦值給函數(shù)變量),否則會出現(xiàn)編譯錯誤。

  • 導(dǎo)入包不要出現(xiàn)循環(huán)依賴,這樣會導(dǎo)致程序編譯失敗

  • Go程序僅僅想要用一個package的init執(zhí)行,我們可以這樣使用:import _ "test_xxxx",導(dǎo)入包的時候加上下劃線就ok了

  • 包級別的變量初始化、init函數(shù)執(zhí)行,這兩個操作都是在同一個goroutine中調(diào)用的,按順序調(diào)用,一次一個包

總結(jié)

好啦,這篇文章到這里就結(jié)束了,本身init函數(shù)就很好理解,寫這篇文章的目的就是讓大家了解他的執(zhí)行順序,這樣在日常開發(fā)中才不會寫出bug。希望本文對大家有所幫助,我們下期見!

素質(zhì)三連(分享、點贊、在看)都是筆者持續(xù)創(chuàng)作更多優(yōu)質(zhì)內(nèi)容的動力!我是asong,我們下期見。

總結(jié)

以上是生活随笔為你收集整理的神奇的 Go init 函数的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。