亚洲国产日韩欧美一区二区三区,精品亚洲国产成人av在线,国产99视频精品免视看7,99国产精品久久久久久久成人热,欧美日韩亚洲国产综合乱

搜索

用八個demo搞懂Go語言defer的五大特性

藏色散人
發(fā)布: 2023-04-23 17:40:51
轉(zhuǎn)載
1624人瀏覽過

在 go 語言中使用 defer 關(guān)鍵字可以將代碼延遲到函數(shù)結(jié)束之前執(zhí)行。在開發(fā)中,我們經(jīng)常使用defer關(guān)鍵字完成善后工作,如關(guān)閉打開的文件描述符、關(guān)閉連接以及釋放資源等。

func demo0() {
    fileName := "./test.txt"
    f, _ := os.OpenFile(fileName, os.O_RDONLY, 0)
    defer f.Close()

    contents, _ := ioutil.ReadAll(f)
    fmt.Println(string(contents))}
登錄后復制

defer關(guān)鍵字一般緊跟在打開資源代碼的后面,防止后續(xù)忘記釋放資源,defer 聲明的代碼實際上要等到函數(shù)結(jié)束之前才會被執(zhí)行。defer 雖然簡單易用,但如果忽略了它的特性,就會在開發(fā)中面臨困惑。于是,我總結(jié)了 defer 的五大特性,通過 8 個demo逐步介紹 defer 的特性。

特性1:多個 defer 時的調(diào)用順序:先進后出

使用多個 defer 關(guān)鍵字時,先被聲明的 defer 語句后被調(diào)用。類似于“?!?strong>先進后出的特性,defer 的這一特性也很好理解,先被打開的資源,可能會被后續(xù)代碼依賴,所以要后釋放才安全。

func demo1() {
    for i := 0; i < 5; i++ {
        defer fmt.Println("defer:", i)
    }}// defer: 4// defer: 3// defer: 2// defer: 1// defer: 0
登錄后復制

特性2:作用域為當前函數(shù),不同函數(shù)下?lián)碛胁煌?defer 棧

運行 demo2 ,從結(jié)果中可以看出,第一個匿名函數(shù)和第二個匿名函數(shù)的 defer 執(zhí)行順序沒有關(guān)系。
defer 作用域僅為當前函數(shù),在當前函數(shù)最后執(zhí)行,所以不同函數(shù)下?lián)碛胁煌?defer 棧。

func demo2() {
    func() {
        defer fmt.Println(1)
        defer fmt.Println(2)
    }()

    fmt.Println("=== 新生代農(nóng)民工啊 ===")

    func() {
        defer fmt.Println("a")
        defer fmt.Println("b")
    }()}// 2// 1// === 新生代農(nóng)民工啊 ===// b// a
登錄后復制

特性3:defer 后的函數(shù)形參在聲明時確認(預計算參數(shù))

運行 demo3_1 ,根據(jù)結(jié)果,我們可以得出:defer 在聲明時,就已經(jīng)確認了形參n的值,而不是在執(zhí)行時確認的;所以,后續(xù)變量 num 無論如何改變都不影響 defer 的輸出結(jié)果。

立即學習go語言免費學習筆記(深入)”;

func demo3_1() {
    num := 0
    defer func(n int) {
        fmt.Println("defer:", n)
    }(num)
    // 等同 defer fmt.Println("defer:", num)

    for i := 0; i < 10; i++ {
        num++
    }

    fmt.Println(num)}//10//defer: 0
登錄后復制

運行 demo3_2,為什么這里 defer 的最終輸出的結(jié)果會和變量 num 相同?因為這里使用的是指針。
defer 聲明時,已經(jīng)確認了形參p指針的指向地址,指向變量 num;后續(xù)變量 num 發(fā)生改變。所以在 defer 執(zhí)行時,輸出的是p指針指向的變量num的當前值。

func demo3_2() {
    num := 0
    p := &num    defer func(p *int) {
        fmt.Println("defer:", *p)
    }(p)

    for i := 0; i < 10; i++ {
        num++
    }

    fmt.Println(*p)}//10//defer: 10
登錄后復制

再看一下 demo3_3,defer 打印的變量并沒有通過函數(shù)參數(shù)傳入,在defer執(zhí)行時,才獲取的”全局變量”num,所以 defer 輸出結(jié)果與變量num一致。

func demo3_3() {
    num := 0
    defer func() {
        fmt.Println("defer:", num)
    }()

    for i := 0; i < 10; i++ {
        num++
    }

    fmt.Println(num)}//10//defer: 10
登錄后復制

特性4:return 與 defer 執(zhí)行順序:return 先 defer 后

運行 demo4_1,可以發(fā)現(xiàn) defer、return 都是在函數(shù)最后執(zhí)行,但 return 先于 defer 執(zhí)行;

func demo4_1() (int, error) {
    defer fmt.Println("defer")
    return fmt.Println("return")}// return// defer
登錄后復制

這一點從輸出結(jié)果上顯而易見,但當 return、defer 的執(zhí)行順序和**函數(shù)返回值**“相遇”時,又將會產(chǎn)生許多復雜的場景。
在 demo4_2 中,函數(shù)使用命名返回值,最終輸出結(jié)果為7。其中經(jīng)歷了這幾個過程:

  1. (首先)變量 num 作為返回值,初始值為0;

  2. (其次)隨后變量 num 被賦值為 10;

  3. (然后)return 時,變量 num 作為返回值被重新賦值為 2;

  4. (接著)defer 在 return 后執(zhí)行,拿到變量 num 進行修改,值為7;

    天工大模型
    天工大模型

    中國首個對標ChatGPT的雙千億級大語言模型

    天工大模型115
    查看詳情 天工大模型
  5. (最后)變量 num 作為返回值,最終函數(shù)返回結(jié)果為7;

    func demo4_2() (num int) {
     num = 10
     defer func() {
         num += 5
     }()
    
     return 2}// 7
    登錄后復制

再來看一個例子。
在 demo4_3 中,函數(shù)使用匿名返回值,最終結(jié)果輸出為2。其中經(jīng)歷的過程是這樣的:

  1. 進入函數(shù),此時返回值變量并未創(chuàng)建;

  2. 創(chuàng)建變量 num,賦值為 10;

  3. return 時創(chuàng)建函數(shù)返回值變量,并賦值為2;這個返回值變量你可以把它看成匿名變量,或者是變量 a、b、c、d……,但它就不是變量 num;

  4. defer 時,無論怎樣修改變量 num,都與函數(shù)返回值無關(guān);

  5. 所以,最終的函數(shù)返回結(jié)果為2;

    func demo4_3() int {
     num := 10
     defer func() {
         num += 5
     }()
    
     return 2}// 2
    登錄后復制

    特性5:發(fā)生 panic 時,已聲明的 defer 會出棧執(zhí)行

    運行 demo5_1,可以看到當出現(xiàn) panic 時,會觸發(fā)已經(jīng)聲明的 defer 出棧執(zhí)行,隨后在再 panic,而在 panic 之后聲明的 defer 將得不到執(zhí)行。

    func demo5_1() {
     defer fmt.Println(1)
     defer fmt.Println(2)
     defer fmt.Println(3)
    
     panic("沒點贊異常") // 觸發(fā)defer出棧執(zhí)行
    
     defer fmt.Println(4) // 得不到執(zhí)行}
    登錄后復制

    正是利用這個特性,在 defer 中可以通過 recover 捕獲 panic,防止程序崩潰。

    func demo5_2() {
     defer func() {
         if err := recover(); err != nil {
             fmt.Println(err, "問題不大")
         }
     }()
    
     panic("沒點贊異常") // 觸發(fā)defer出棧執(zhí)行
    
     // ...}
    登錄后復制

    完整代碼:github.com/newbugcoder/learngo/tre...

以上就是用八個demo搞懂Go語言defer的五大特性的詳細內(nèi)容,更多請關(guān)注php中文網(wǎng)其它相關(guān)文章!

相關(guān)標簽:
最佳 Windows 性能的頂級免費優(yōu)化軟件
最佳 Windows 性能的頂級免費優(yōu)化軟件

每個人都需要一臺速度更快、更穩(wěn)定的 PC。隨著時間的推移,垃圾文件、舊注冊表數(shù)據(jù)和不必要的后臺進程會占用資源并降低性能。幸運的是,許多工具可以讓 Windows 保持平穩(wěn)運行。

下載
來源:learnku網(wǎng)
本文內(nèi)容由網(wǎng)友自發(fā)貢獻,版權(quán)歸原作者所有,本站不承擔相應法律責任。如您發(fā)現(xiàn)有涉嫌抄襲侵權(quán)的內(nèi)容,請聯(lián)系admin@php.cn
最新問題
開源免費商場系統(tǒng)廣告
最新下載
更多>
網(wǎng)站特效
網(wǎng)站源碼
網(wǎng)站素材
前端模板
關(guān)于我們 免責申明 意見反饋 講師合作 廣告合作 最新更新
php中文網(wǎng):公益在線php培訓,幫助PHP學習者快速成長!
關(guān)注服務號 技術(shù)交流群
PHP中文網(wǎng)訂閱號
每天精選資源文章推送
PHP中文網(wǎng)APP
隨時隨地碎片化學習
PHP中文網(wǎng)抖音號
發(fā)現(xiàn)有趣的

Copyright 2014-2025 http://ipnx.cn/ All Rights Reserved | php.cn | 湘ICP備2023035733號