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

golang中的defer函數(shù)理解

 更新時間:2022年10月24日 16:11:58   作者:西京刀客  
defer是Go語言中的延遲執(zhí)行語句,用來添加函數(shù)結(jié)束時執(zhí)行的代碼,常用于釋放某些已分配的資源、關(guān)閉數(shù)據(jù)庫連接、斷開socket連接、解鎖一個加鎖的資源,這篇文章主要介紹了golang中的defer函數(shù)理解,需要的朋友可以參考下

golang的defer

什么是defer

defer的的官方文檔:https://golang.org/ref/spec#Defer_statements

go語言中defer可以完成延遲功能,當(dāng)前函數(shù)執(zhí)行完成后再執(zhí)行defer的代碼塊。通過defer,我們可以在代碼中優(yōu)雅的關(guān)閉/清理代碼中所使用的變量。

defer是Go語言中的延遲執(zhí)行語句,用來添加函數(shù)結(jié)束時執(zhí)行的代碼,常用于釋放某些已分配的資源、關(guān)閉數(shù)據(jù)庫連接、斷開socket連接、解鎖一個加鎖的資源。

Go語言機(jī)制擔(dān)保一定會執(zhí)行defer語句中的代碼。其它語言中也有類似的機(jī)制,比如Java、C#語言里的finally語句,C++語言里的析構(gòu)函數(shù)(Destructor)可以起類似的作用,C++語言機(jī)制擔(dān)保在對象被銷毀前一定會執(zhí)行析構(gòu)函數(shù)中的代碼。C++中的析構(gòu)函數(shù)析構(gòu)的是對象,Go中的defer析構(gòu)的是函數(shù)。

理解defer

defer什么時間執(zhí)行(defer、 return、返回值 三者的執(zhí)行順序)

defer只有在當(dāng)前函數(shù)執(zhí)行完畢后,才會執(zhí)行。描述其實不太精確

go中的return語句并不是原子性操作,一般是分為兩步:

  • 將返回值賦值給一個變量
  • 執(zhí)行RET指令

return并不是原子性操作,是通過一個變量賦值和ret指令來完成的。defer就執(zhí)行在1之后,2之前。defer的執(zhí)行順序在return之后,但是在返回值返回給調(diào)用方之前,所以使用defer可以達(dá)到修改返回值的目的。

defer、 return、返回值 三者的執(zhí)行順序是 : return 最先給返回值賦值;接著 defer 開始執(zhí)行一些收尾工作;最后 RET 指令攜帶返回值退出函數(shù)。

package main

import (
    "fmt"
)

func main() {
    ret := test()
    fmt.Println("test return:", ret)
}
// func test() ( int) {  這種就是匿名返回值
//返回值改為命名返回值, 具名返回值。即返回值帶有名字, 這樣我們在執(zhí)行defer的時候相當(dāng)于修改了返回值的值
func test() (i int) {
    //var i int

    defer func() {
        i++
        fmt.Println("test defer, i = ", i)
    }()

    return i
}

注意: 這塊驗證使用了具名返回值 func test() (i int) { 中的(i int) 。 測試結(jié)果滿足我們預(yù)期。

編碼中,我們要特別注意, go語言中匿名返回值和命名返回值對defer的影響。不過一般我們都是使用命名返回值。

一個主函數(shù)擁有一個匿名的返回值,返回時使用字面值,比如返回”1”、”2”、”Hello”這樣的值,這種情況下defer語句是無法操作返回值的。

defer輸出的值,就是定義時的值。而不是defer真正執(zhí)行時的變量值(注意引用情況)

defer函數(shù)會在return之后被調(diào)用。那么這段函數(shù)執(zhí)行完之后,是不用應(yīng)該輸出1呢?

package main

import "fmt"

func test1() {
	i := 0
	defer fmt.Println(i)
	i++
	return
}

func main() {
	test1()
}

輸出結(jié)果:0

雖然我們在defer后面定義的是一個帶變量的函數(shù): fmt.Println(i). 但這個變量(i)在defer被聲明的時候,就已經(jīng)確定其確定的值了。

總結(jié): 因為defer后面的函數(shù)在入棧的時候保存的是入棧那一刻的值,而當(dāng)時i的值是0,所以后期對i修改,并不會影響棧內(nèi)函數(shù)的值。

我們再看下一個例子:

package main

import "fmt"


func test2() {
	x := 10
	defer func(a *int) {
		fmt.Println(*a)
	}(&x)
	x++
}

func main() {
	test2()
}

輸出結(jié)果: 11

這里為什么和前面結(jié)論不一樣呢?
這里defer后面函數(shù)入棧的時候存入的執(zhí)行變量x的指針。所以,后期x值改變的時候,輸出結(jié)果也會改變。

總結(jié): 需要注意引用情況。對于指針類型參數(shù),規(guī)則仍然適用,只不過延遲函數(shù)的參數(shù)是一個地址值,這種情況下,defer后面的語句對變量的修改會影響延遲函數(shù)。

多個defer,執(zhí)行順序

package main

import (
    "fmt"
)

func main() {
    defer fmt.Println("main defer1")
    test()
    defer fmt.Println("main defer2")
}

func test() () {
    defer func() {
        fmt.Println("test defer1")
    }()
    defer func() {
        fmt.Println("test defer2")
    }()
}

輸出結(jié)果:

test defer2
test defer1
main defer2
main defer1

總結(jié): 后進(jìn)先出(LIFO)的順序執(zhí)行,即先出現(xiàn)的 defer 最后執(zhí)行。即:多個defer語句的執(zhí)行順序是逆序執(zhí)行。

defer的函數(shù)一定會執(zhí)行么?

defer是Go語言中的延遲執(zhí)行語句,用來添加函數(shù)結(jié)束時執(zhí)行的代碼,常用于釋放某些已分配的資源、關(guān)閉數(shù)據(jù)庫連接、斷開socket連接、解鎖一個加鎖的資源。

Go語言機(jī)制擔(dān)保一定會執(zhí)行defer語句中的代碼。其它語言中也有類似的機(jī)制,比如Java、C#語言里的finally語句,C++語言里的析構(gòu)函數(shù)(Destructor)可以起類似的作用,C++語言機(jī)制擔(dān)保在對象被銷毀前一定會執(zhí)行析構(gòu)函數(shù)中的代碼。C++中的析構(gòu)函數(shù)析構(gòu)的是對象,Go中的defer析構(gòu)的是函數(shù)。

panic情況

網(wǎng)上demo:

package main

import (
	"fmt"
)

func test1() {
	fmt.Println("test")
}

func test2() {
	panic(1)
}
func main() {
	fmt.Println("main start")
	defer test1()
	test2() //造panic
	fmt.Println("main end")
}

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

main start
test                                                                  
panic: 1                                                                                                                                   
goroutine 1 [running]:                                                
main.test2(...)         

總結(jié): 我們發(fā)現(xiàn)正常的panic,還是會調(diào)我們的defer的,并且在會在panic之前執(zhí)行。

os.Exit情況

網(wǎng)上demo:

package main

import (
	"fmt"
	"os"
)

func test1() {
	fmt.Println("test")
}

func main() {
	fmt.Println("main start")
	defer test1()
	fmt.Println("main end")
	os.Exit(0)
}

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

main start
main end

總結(jié): 如果在當(dāng)前函數(shù)里是因為執(zhí)行了os.Exit退出,而不是正常return退出或者panic退出,那程序會立即停止,被defer的函數(shù)調(diào)用不會執(zhí)行。

kill情況(Ctrl+C)

package main

import (
	"fmt"
	"time"
)

func test1() {
	fmt.Println("test")
}

func test2() {
	time.Sleep(60 * time.Second)
}
func main() {
	fmt.Println("main start")
	defer test1()
	test2()
	fmt.Println("main end")
}

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

main start

Process finished with the exit code -1073741510 (0xC000013A: interrupted by Ctrl+C)

如上,我們test2() 睡眠時間內(nèi),點擊Ctrl+C,發(fā)現(xiàn)defer test1()并沒有執(zhí)行。

總結(jié):這個點很重要,需要我們在日常異常中斷時,留意defer是否未處理的情況。
所以一般情況下,我們程序需要捕獲這種異常中斷,在程序退出前,手動做一些處理。

參考文獻(xiàn)

Go常見坑:Go語言里被defer的函數(shù)一定會執(zhí)行么?
參考URL: https://blog.csdn.net/perfumekristy/article/details/121343642
面試官:聽說你精通golang的defer?
參考URL: https://cloud.tencent.com/developer/article/2076951

到此這篇關(guān)于golang中的defer函數(shù)理解的文章就介紹到這了,更多相關(guān)golang defer函數(shù)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • GoLang使goroutine停止的五種方法實例

    GoLang使goroutine停止的五種方法實例

    goroutine是Go并行設(shè)計的核心,下面這篇文章主要給大家介紹了關(guān)于GoLang使goroutine停止的五種方法,文中通過實例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2022-07-07
  • 一文詳解Golang中的errors包

    一文詳解Golang中的errors包

    在 Golang 中,errors 包是用于處理錯誤的標(biāo)準(zhǔn)庫, errors 包提供的功能比較簡單,使用起來非常方便,接下來就具體講解一下 errors 包提供的幾個函數(shù),感興趣的小伙伴跟著小編一起來看看吧
    2023-07-07
  • golang如何替換換行符

    golang如何替換換行符

    這篇文章主要介紹了golang如何替換換行符問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-07-07
  • Golang函數(shù)重試機(jī)制實現(xiàn)代碼

    Golang函數(shù)重試機(jī)制實現(xiàn)代碼

    在編寫應(yīng)用程序時,有時候會遇到一些短暫的錯誤,例如網(wǎng)絡(luò)請求、服務(wù)鏈接終端失敗等,這些錯誤可能導(dǎo)致函數(shù)執(zhí)行失敗,這篇文章主要介紹了Golang函數(shù)重試機(jī)制實現(xiàn)代碼,需要的朋友可以參考下
    2024-04-04
  • go語言使用scp的方法實例分析

    go語言使用scp的方法實例分析

    這篇文章主要介紹了go語言使用scp的方法,實例分析了go語言調(diào)用scp命令的使用技巧,具有一定參考借鑒價值,需要的朋友可以參考下
    2015-03-03
  • 如何組織Go代碼目錄結(jié)構(gòu)依賴注入wire使用解析

    如何組織Go代碼目錄結(jié)構(gòu)依賴注入wire使用解析

    這篇文章主要為大家介紹了如何組織Go代碼目錄結(jié)構(gòu)依賴注入wire使用解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-07-07
  • 詳解Go中如何進(jìn)行進(jìn)行內(nèi)存優(yōu)化和垃圾收集器管理

    詳解Go中如何進(jìn)行進(jìn)行內(nèi)存優(yōu)化和垃圾收集器管理

    這篇文章主要為大家詳細(xì)介紹了Go中如何進(jìn)行進(jìn)行內(nèi)存優(yōu)化和垃圾收集器管理,文中的示例代碼講解詳細(xì),具有一定的學(xué)習(xí)價值,感興趣的小伙伴可以了解下
    2023-11-11
  • golang如何實現(xiàn)抓取IP地址的蜘蛛程序詳解

    golang如何實現(xiàn)抓取IP地址的蜘蛛程序詳解

    這篇文章主要給大家介紹了關(guān)于利用golang如何實現(xiàn)抓取IP地址的蜘蛛程序的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2018-07-07
  • Go語言的代碼組織結(jié)構(gòu)詳細(xì)介紹

    Go語言的代碼組織結(jié)構(gòu)詳細(xì)介紹

    這篇文章主要介紹了Go語言的代碼碼組織結(jié)構(gòu)詳細(xì)介紹,即Go語言源碼的文件結(jié)構(gòu),本文講解了包、main和main.main、os包等內(nèi)容,需要的朋友可以參考下
    2014-10-10
  • 使用golang開發(fā)一個curl命令行工具

    使用golang開發(fā)一個curl命令行工具

    這篇文章主要為大家詳細(xì)介紹了如何使用golang開發(fā)一個簡單的curl命令行工具,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2023-11-11

最新評論

彰化市| 中江县| 鸡泽县| 甘谷县| 马山县| 曲水县| 海兴县| 寿宁县| 错那县| 江城| 毕节市| 监利县| 宁化县| 梁平县| 抚顺县| 杭锦旗| 平湖市| 龙海市| 太仓市| 安福县| 平顶山市| 华安县| 黄骅市| 彩票| 玛纳斯县| 子长县| 拉孜县| 无锡市| 河间市| 马关县| 紫金县| 象山县| 滦南县| 和政县| 普定县| 安义县| 吕梁市| 甘泉县| 黎城县| 江津市| SHOW|