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

Go語言函數(shù)的延遲調(diào)用(Deferred Code)詳解

 更新時間:2022年07月12日 08:18:20   作者:孫琦Ray  
本文將介紹Go語言函數(shù)和方法中的延遲調(diào)用,正如名稱一樣,這部分定義不會立即執(zhí)行,一般會在函數(shù)返回前再被調(diào)用,我們通過一些示例來了解一下延遲調(diào)用的使用場景

先解釋一下這篇Blog延期的原因,本來已經(jīng)準備好了全部內(nèi)容,但是當我重新回顧實例三的時候,發(fā)現(xiàn)自己還是存在認知不足的地方,于是為了準確表述,查閱了大量的資料,重新編寫了第三部分,導(dǎo)致延期。感謝持續(xù)關(guān)注本筆記更新的朋友,后期我將逐步通過3-5分鐘視頻方式為大家對筆記內(nèi)容進行講解,幫助更多的朋友能夠快速掌握Go語言的基礎(chǔ)。

本節(jié)將介紹Go語言函數(shù)和方法中的延遲調(diào)用,正如名稱一樣,這部分定義不會立即執(zhí)行,一般會在函數(shù)返回前再被調(diào)用,我們通過下面的幾個示例來了解一下延遲調(diào)用的使用場景。

基本功能

在以下這段代碼中,我們操作一個文件,無論成功與否都需要關(guān)閉文件句柄。這里在三處不同的位置都調(diào)用了file.Close()方法,代碼顯得非常冗余。

func ReadWrite() bool {
    file.Open("file")
    // Do your thing
    if failureX {
        file.Close()
        return false
    }

    if failureY {
        file.Close()
        return false
    }
    file.Close()
    return true
}

我們利用延遲調(diào)用來優(yōu)化代碼。定義后的defer代碼,會在return之前返回,讓代碼顯得更加緊湊,且可讀性變強,對上面的代碼改造如下:

func ReadWrite() bool {
    file.Open("filename")
    // Define a defer code here
    defer file.Close()
    // Do your thing
    if failureX {
        return false
    }
    if failureY {
        return false
    }
    return true
}

示例一:延遲調(diào)用執(zhí)行順序

我們通過這個示例來看一下延遲調(diào)用與正常代碼之間的執(zhí)行順序

package main

import "fmt"

func TestDefer(x int) {
    defer fmt.Println("Defer code called")
    switch x {
    case 1:
        fmt.Println("Case 1 triggered!")
        return
    case 10:
        fmt.Println("Case 10 triggered!")
        return
    default:
        fmt.Println("Case default triggered!")
        return
    }
}

func main() {
    TestDefer(100)
    TestDefer(1)
    TestDefer(10)
}

先簡單分析一下代碼邏輯:

  • 首先定義了一個公共的TestDefer函數(shù),這個函數(shù)接受一個整型的參數(shù)
  • 函數(shù)體內(nèi)定義了defer部分,會輸出一句Defer code called
  • switch case會根據(jù)輸入的整型參數(shù),輸出相應(yīng)的trigger語句
  • 按照上面對延遲調(diào)用的分析,每次滿足case語句后,才會輸出Defer code called

從輸出中,我們可以觀察到如下現(xiàn)象:

  • 首次執(zhí)行,default條件滿足,Case default triggered先輸出,再輸出defer內(nèi)容
  • 第二次調(diào)用,1條件滿足,最后輸出defer內(nèi)容
  • 第三次調(diào)用,10條件滿足,最后輸出defer內(nèi)容

從這個實例中,我們很明顯觀察到,defer語句是在return之前執(zhí)行

Case default triggered!
Defer code called
Case 1 triggered!
Defer code called
Case 10 triggered!
Defer code called

示例二:多defer使用方法

package main

import "fmt"

func TestDefer(x int) {
    defer fmt.Println("1st defined Defer code called")
    defer fmt.Println("2nd defined Defer code called")
    defer fmt.Println("3rd defined Defer code called")
    switch x {
    case 1:
        fmt.Println("Case 1 triggered!")
        return
    case 10:
        fmt.Println("Case 10 triggered!")
        return
    default:
        fmt.Println("Case default triggered!")
        return
    }
}

func main() {
    TestDefer(100)
}

仍然是相同的例子,但是在TestDefer中我們定義了三個defer輸出,根據(jù)LIFO原則,輸出的順序是3rd->2nd->1st,根據(jù)最后的結(jié)果,也是逆向向上執(zhí)行defer輸出。

Case default triggered!
3rd defined Defer code called
2nd defined Defer code called
1st defined Defer code called

實例三:defer與局部變量、返回值的關(guān)系

就在整理這篇筆記的時候,發(fā)現(xiàn)了自己的認知誤區(qū),主要是本節(jié)實例三中發(fā)現(xiàn)的,先來看一下英文的描述:

A defer statement pushes a function call onto a list. The list of saved calls is executed after the surrounding function returns. Defer is commonly used to simplify functions that perform various clean-up actions.

對于上面的這段話的理解:

defer定義的函數(shù)會被放入list中

存儲的defer函數(shù)會在周邊函數(shù)返回后執(zhí)行

defer一般用于環(huán)境清理

原則一:defer函數(shù)的參數(shù)值,取決于defer函數(shù)調(diào)用時變量的值

package main

import "fmt"

func a() int {
    i := 0
    fmt.Printf("func i = %v\n", i)
    defer fmt.Printf("defer i = %v\n", i)
    i++
    fmt.Printf("func i = %v\n", i)
    defer fmt.Printf("defer after i++ = %v\n", i)
    return i
}

func main() {
    i := a()
    fmt.Printf("main i = %v\n", i)
}

下面是代碼執(zhí)行輸出,我們來一起分析一下:

  • 在函數(shù)a中,定義了局部變量i
  • 在函數(shù)執(zhí)行過程中進行了自增操作i++
  • 分別在i++前后,對i值進行了輸出,也就是我們下面輸出結(jié)果前兩行,與預(yù)期一致
  • 分別在i++前后,定義兩個defer語句,都是用fmt輸出i的值,輸出的順序與示例二的邏輯一致,先輸出的是defer after,再輸出defer
  • 根據(jù)原則一,在defer after的輸出中,由于i++完成自增,所以當時i的值已經(jīng)變?yōu)榱?,所以輸出為1
  • 同樣是根據(jù)原則一,在defer的輸出中,i并沒有進行自增,所以在當時情況下,i的值仍然為0,所以輸出為0
  • 最后返回的i值為1,主函數(shù)中輸出i的值為1
func i = 0
func i = 1
defer after i++ = 1
defer i = 0
main i = 1

原則二:defer可以讀取或修改顯示定義的返回值

package main

import "fmt"

func a() (i int) {
    fmt.Printf("func initial i = %v\n", i)
    defer func() {
        fmt.Printf("defer func initial i++ = %v\n", i)
        i++
        fmt.Printf("defer func after i++ = %v\n", i)
    }()
    fmt.Printf("func before return i = %v\n", i)
    return 10
}

func main() {
    i := a()
    fmt.Printf("main i = %v\n", i)
}

雖然在a()函數(shù)內(nèi),顯示的返回了10,但是main函數(shù)中得到的結(jié)果是defer函數(shù)自增后的結(jié)果,我們來分析一下代碼:

在a函數(shù)定義時,我們顯示的定義了返回變量i和類型int

在剛剛進入函數(shù)時,i的初始化值位0,返回前也是0

在最后的return時,直接返回了10

接著我們再來看defer函數(shù)執(zhí)行情況,剛剛進入defer函數(shù)時,返回值i得到的值正是剛才返回的10

而在自增后,i的值變成了11

最后我們在主函數(shù)中,獲得的返回值也是11,印證了我們原則中的defer函數(shù)對于返回值的讀取和修改

func initial i = 0
func before return i = 0
defer func initial i++ = 10
defer func after i++ = 11
main i = 11

到此這篇關(guān)于Go語言函數(shù)的延遲調(diào)用(Deferred Code)詳解的文章就介紹到這了,更多相關(guān)Go 函數(shù)延遲調(diào)用內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 徹底理解golang中什么是nil

    徹底理解golang中什么是nil

    這篇文章主要介紹了golang中的nil用法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2021-04-04
  • golang爬蟲colly?發(fā)送post請求

    golang爬蟲colly?發(fā)送post請求

    本文主要介紹了golang爬蟲colly?發(fā)送post請求實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-07-07
  • Golang?Fasthttp選擇使用slice而非map?存儲請求數(shù)據(jù)原理探索

    Golang?Fasthttp選擇使用slice而非map?存儲請求數(shù)據(jù)原理探索

    本文將從簡單到復(fù)雜,逐步剖析為什么?Fasthttp?選擇使用?slice?而非?map,并通過代碼示例解釋這一選擇背后高性能的原因,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2024-02-02
  • golang qq郵件發(fā)送驗證碼功能

    golang qq郵件發(fā)送驗證碼功能

    驗證碼在多個場景下發(fā)揮著重要作用,如注冊/登錄、短信接口保護、提交/投票、密碼找回和支付驗證等,以保障賬號安全和防止惡意操作,此外,文章還介紹了使用golang通過qq郵件發(fā)送驗證碼的實現(xiàn)過程,包括獲取授權(quán)碼、下載依賴包和編寫代碼,感興趣的朋友跟隨小編一起看看吧
    2024-09-09
  • go語言執(zhí)行windows下命令行的方法

    go語言執(zhí)行windows下命令行的方法

    這篇文章主要介紹了go語言執(zhí)行windows下命令行的方法,實例分析了Go語言操作windows下命令行的技巧,需要的朋友可以參考下
    2015-03-03
  • 詳解Go如何基于現(xiàn)有的context創(chuàng)建新的context

    詳解Go如何基于現(xiàn)有的context創(chuàng)建新的context

    在?Golang?中,context?包提供了創(chuàng)建和管理上下文的功能,那么在GO語言中如何基于現(xiàn)有的context創(chuàng)建新的context,下面小編就來和大家詳細聊聊
    2024-01-01
  • go?singleflight緩存雪崩源碼分析與應(yīng)用

    go?singleflight緩存雪崩源碼分析與應(yīng)用

    這篇文章主要為大家介紹了go?singleflight緩存雪崩源碼分析與應(yīng)用示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-09-09
  • golang實現(xiàn)整型和字節(jié)數(shù)組之間的轉(zhuǎn)換操作

    golang實現(xiàn)整型和字節(jié)數(shù)組之間的轉(zhuǎn)換操作

    這篇文章主要介紹了golang實現(xiàn)整型和字節(jié)數(shù)組之間的轉(zhuǎn)換操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-12-12
  • go語言區(qū)塊鏈學(xué)習(xí)調(diào)用以太坊

    go語言區(qū)塊鏈學(xué)習(xí)調(diào)用以太坊

    這篇文章主要為大家介紹了go語言區(qū)塊鏈學(xué)習(xí)如何調(diào)用以太坊的示例實現(xiàn)過程,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步
    2021-10-10
  • golang 內(nèi)存對齊的實現(xiàn)

    golang 內(nèi)存對齊的實現(xiàn)

    在代碼編譯階段,編譯器會對數(shù)據(jù)的存儲布局進行對齊優(yōu)化,本文主要介紹了golang 內(nèi)存對齊的實現(xiàn),具有一定的參考價值,感興趣的可以了解一下
    2024-08-08

最新評論