簡單聊聊Golang中defer預(yù)計算參數(shù)
什么是defer
defer用來聲明一個延遲函數(shù),把這個函數(shù)放入到一個棧上, 當(dāng)外部的包含方法return之前,返回參數(shù)到調(diào)用方法之前調(diào)用,也可以說是運行到最外層方法體的"}"時調(diào)用。我們經(jīng)常用他來做一些資源的釋放,比如關(guān)閉io操作
func doSomething(fileName string) { file,err := os.Open(fileName) if err != nil { panic(err) } defer file.Close() }
defer 可以保證方法可以在外圍函數(shù)返回之前調(diào)用。有點像其他言的 try finally
try{ }finally{ }
Go語言defer預(yù)計算參數(shù)
Go 語言中所有的函數(shù)調(diào)用都是傳值的,雖然 defer 是關(guān)鍵字,但是也繼承了這個特性。假設(shè)我們想要計算 main 函數(shù)運行的時間,可能會寫出以下的代碼:
package main import ( "fmt" "time" ) func main() { startedAt := time.Now() defer fmt.Println(time.Since(startedAt)) time.Sleep(time.Second) //休眠一秒 }
結(jié)果是:
D:\workspace\go\src\test>go run main.go
0s
運行結(jié)果并不符合我們的預(yù)期,這個現(xiàn)象背后的原因是什么呢?經(jīng)過分析,我們會發(fā)現(xiàn)調(diào)用 defer 關(guān)鍵字會立刻拷貝函數(shù)中引用的外部參數(shù),所以 time.Since(startedAt) 的結(jié)果不是在 main 函數(shù)退出之前計算的,而是在 defer 關(guān)鍵字調(diào)用時計算的【defer入棧的時候】,最終導(dǎo)致上述代碼輸出 0s
我們再來看個簡單例子來說明上述解釋:
package main import ( "fmt" ) func main() { i := 1 defer fmt.Println(test(i)) i = 100 } func test(i int) int { i = i + 1 return i } D:\workspace\go\src\test>go run main.go 2
當(dāng)代碼運行到defer fmt.Println(test(i))的時候,會把defer右邊最外層函數(shù)的參數(shù)計算完畢,并傳遞進函數(shù)里,但不會執(zhí)行函數(shù)體的代碼直到包裹defer的函數(shù)返回。我們先看會把defer右邊最外層函數(shù)的參數(shù)計算完畢,并傳遞進函數(shù)里這句話,對應(yīng)例子就是先把test(i)算出來,此時i=1,計算test(1)得2,然后fmt.Println(2)入棧,等到最后程序運行完了再運行defer結(jié)果就是2(但不會執(zhí)行函數(shù)體的代碼直到包裹defer的函數(shù)返回)。
我們再來看一個例子與匿名函數(shù)結(jié)合:
package main import ( "fmt" ) func main() { i := 1 defer func() { fmt.Println(test(i)) }() i = 100 } func test(i int) int { i = i + 1 return i }
結(jié)果:
D:\workspace\go\src\test>go run main.go
101
使用匿名函數(shù),結(jié)果是101,相當(dāng)于i給到test方法的是100,那為什么呢?還是那句話:但不會執(zhí)行函數(shù)體的代碼直到包裹defer的函數(shù)返回
也就是說他會把整個{ fmt.Println(test(i)) }()函數(shù)體入棧,等到最后程序運行完了再運行defer,此時的i是100,運行test后就是101了。
所以你要解決第一個打印為0s的問題,你就可以使用匿名函數(shù)來解決,如下:
package main import ( "fmt" "time" ) func main() { startedAt := time.Now() defer func() { fmt.Println(time.Since(startedAt)) }() time.Sleep(time.Second) //休眠一秒 }
結(jié)果:
D:\workspace\go\src\test>go run main.go
1.0152825s
總結(jié)
到此這篇關(guān)于Golang中defer預(yù)計算參數(shù)的文章就介紹到這了,更多相關(guān)Go defer預(yù)計算參數(shù)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
golang通過node_exporter監(jiān)控GPU及cpu頻率、溫度的代碼
node_exporter這個開源組件是配合prometheus收集主機操作系統(tǒng)層的metrics的常用組件,但是官方?jīng)]有提供GPU卡的metrics的采集,今天通過本文給大家介紹golang通過node_exporter監(jiān)控GPU及cpu頻率、溫度的相關(guān)知識,感興趣的朋友一起看看吧2022-05-05Golang初始化MySQL數(shù)據(jù)庫方法淺析
這篇文章主要介紹了Golang初始化MySQL數(shù)據(jù)庫的方法,數(shù)據(jù)庫的建立第一步即要初始化,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)吧2023-05-05