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

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)自己還是存在認知不足的地方,于是為了準確表述,查閱了大量的資料,重新編寫了第三部分,導致延期。感謝持續(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開發(fā)中channel使用

    golang開發(fā)中channel使用

    channel[通道]是golang的一種重要特性,正是因為channel的存在才使得golang不同于其它語言。這篇文章主要介紹了golang開發(fā)中channel使用,需要的朋友可以參考下
    2020-09-09
  • 淺談Go1.18中的泛型編程

    淺談Go1.18中的泛型編程

    本文主要介紹了Go1.18中的泛型編程,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-12-12
  • 詳解Go?依賴管理?go?mod?tidy

    詳解Go?依賴管理?go?mod?tidy

    這篇文章主要為大家介紹了詳解Go?依賴管理?go?mod?tidy,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-10-10
  • 使用go操作redis的有序集合(zset)

    使用go操作redis的有序集合(zset)

    這篇文章主要介紹了使用go操作redis的有序集合(zset),具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-12-12
  • 深入理解 Go 語言中的 Context

    深入理解 Go 語言中的 Context

    這篇文章主要介紹了 理解 Go 語言中的 Context,需要的朋友可以參考下
    2020-06-06
  • 用Go語言標準庫實現(xiàn)Web服務(wù)之項目介紹

    用Go語言標準庫實現(xiàn)Web服務(wù)之項目介紹

    從本節(jié)開始將從后端到前端一步一步實現(xiàn)一個Go語言Web服務(wù),后端除了MySQL驅(qū)動,全部使用Go語言標準庫來實現(xiàn)一個小型項目,本篇將簡單的介紹一下項目開發(fā)要準備的流程,感興趣的同學可以閱讀一下
    2023-05-05
  • 解決golang中container/list包中的坑

    解決golang中container/list包中的坑

    這篇文章主要介紹了解決golang中container/list包中的坑,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2021-04-04
  • Go并發(fā)調(diào)用的超時處理的方法

    Go并發(fā)調(diào)用的超時處理的方法

    這篇文章主要介紹了Go并發(fā)調(diào)用的超時處理的方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2019-01-01
  • golang?中?channel?的詳細使用、使用注意事項及死鎖問題解析

    golang?中?channel?的詳細使用、使用注意事項及死鎖問題解析

    這篇文章主要介紹了golang?中?channel?的詳細使用、使用注意事項及死鎖分析,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-03-03
  • 解決golang結(jié)構(gòu)體tag編譯錯誤的問題

    解決golang結(jié)構(gòu)體tag編譯錯誤的問題

    這篇文章主要介紹了解決golang結(jié)構(gòu)體tag編譯錯誤的問題,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2021-05-05

最新評論

台北县| 双牌县| 奉节县| 临海市| 东乡族自治县| 疏勒县| 扶沟县| 资源县| 通辽市| 万年县| 彭泽县| 余干县| 高唐县| 平和县| 砀山县| 康平县| 洞头县| 漳浦县| 安新县| 买车| 台江县| 高州市| 法库县| 麦盖提县| 策勒县| 毕节市| 通海县| 柘荣县| 炉霍县| 沛县| 平昌县| 榆社县| 清远市| 津南区| 霍山县| 拉萨市| 湖南省| 嘉黎县| 宿松县| 鹤峰县| 察雅县|