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

Golang之defer 延遲調(diào)用操作

 更新時(shí)間:2020年12月23日 11:15:51   作者:程序猿編碼  
這篇文章主要介紹了Golang之defer 延遲調(diào)用操作,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧

前言

defer語句被用于預(yù)定對一個(gè)函數(shù)的調(diào)用。我們把這類被defer語句調(diào)用的函數(shù)稱為延遲函數(shù)。而defer 延遲語句在其他編程語言里好像沒有見到。應(yīng)該是屬于 Go 語言里的獨(dú)有的關(guān)鍵字。但用法類似于面向?qū)ο缶幊陶Z言 Java 和 C# 的 finally 語句塊。

下面對defer進(jìn)行介紹。

defer特性

1. 關(guān)鍵字 defer 用于注冊延遲調(diào)用。

2. 這些調(diào)用直到 return 前才被執(zhí)。因此,可以用來做資源清理。

3. 多個(gè)defer語句,按先進(jìn)后出的方式執(zhí)行。

1.延遲調(diào)用

用法很簡單,只需要在函數(shù)前面加上 defer就行,就能實(shí)現(xiàn)將這個(gè) 該函數(shù)的調(diào)用延遲到當(dāng)前函數(shù)執(zhí)行完后再執(zhí)行。例如:

package main 
import (
 "fmt"
)
func myFunc(){
 fmt.Println("minger")
}
func main(){
 defer myFunc() //等價(jià)于defer fmt.Println("minger")
 fmt.Println("程序猿編碼")
}

編譯運(yùn)行:

2.defer 與 return 孰先孰后

defer 和 return 到底是哪個(gè)先調(diào)用?先看看例子:

package main 
import (
 "fmt"
)
var name string = "go"
func myFunc() string {
  defer func() {
    name = "python"
  }()
  fmt.Println("myFunc 函數(shù)里的name:", name)
  return name
}
func main() {
  myName := myFunc()
  fmt.Println("main 函數(shù)里的name: ", name)
  fmt.Println("main 函數(shù)里的myname: ", myName )

編譯運(yùn)行:

來看看打印信息,第一行輸出,name 此時(shí)還是全局變量,值還是go

第二行輸出,在 defer 里改變了全局變量,此時(shí)name的值已經(jīng)變成了 python

重點(diǎn)在第三行,為什么輸出的是 go ?

解釋只有一個(gè),那就是 defer 是return 后才調(diào)用的。所以在執(zhí)行 defer 前,myName 已經(jīng)被賦值成 go 了。

3.多個(gè)defer 逆序執(zhí)行

還是老規(guī)矩先來上代碼,看看輸出信息,例子:

package main 
import (
 "fmt"
)
func main(){
 name := "go"
 defer fmt.Println(name)
 name = "C/C++"
 defer fmt.Println(name)
 name = "Python"
 fmt.Println(name)
}

編譯輸出:

可見 多個(gè)defer 是它們會(huì)以逆序執(zhí)行(類似棧,即后進(jìn)先出)。

defer官方的解釋

Each time a “defer” statement executes, the function value and parameters to the call are evaluated as usual and saved anew but the actual function is not invoked. Instead, deferred functions are invoked immediately before the surrounding function returns, in the reverse order they were deferred. If a deferred function value evaluates to nil, execution panics when the function is invoked, not when the “defer” statement is executed.

翻譯一下:

每次defer語句執(zhí)行的時(shí)候,會(huì)把函數(shù)“壓棧”,函數(shù)參數(shù)會(huì)被拷貝下來;當(dāng)外層函數(shù)(非代碼塊,如一個(gè)for循環(huán))退出時(shí),defer函數(shù)按照定義的逆序執(zhí)行;如果defer執(zhí)行的函數(shù)為nil, 那么會(huì)在最終調(diào)用函數(shù)的產(chǎn)生panic.

為什么需要defer?

往往我們在編程的時(shí)候,經(jīng)常需要打開一些資源,比如數(shù)據(jù)庫連接、文件、鎖等,這些資源需要在用完之后釋放掉,否則會(huì)造成內(nèi)存泄漏。

因此我們有時(shí)會(huì)忘記關(guān)閉這些資源。Golang直接在語言層面提供defer關(guān)鍵字,在打開資源語句的下一行,就可以直接用defer語句來注冊函數(shù)結(jié)束后執(zhí)行關(guān)閉資源的操作。

defer用途

1. 關(guān)閉文件句柄

2. 鎖資源釋放

3. 數(shù)據(jù)庫連接釋放

defer的使用其實(shí)非常簡單,來看看一個(gè)簡單用途:

package main
import (
 "log"
 "os"
)
func main() {
 f, err := os.OpenFile("text.txt", os.O_RDWR|os.O_APPEND|os.O_CREATE, 0666) //文件沒有就創(chuàng)建,文件存在就追加
 if err != nil {
 log.Fatal(err)
 }
 defer f.Close()
 f.WriteString("程序猿編碼\n")
}

編譯輸出:

在打開文件的語句附近,用defer語句關(guān)閉文件。這樣,在函數(shù)結(jié)束之前,會(huì)自動(dòng)執(zhí)行defer后面的語句來關(guān)閉文件。

當(dāng)然,defer會(huì)有小小地延遲,對時(shí)間要求特別特別特別高的程序,可以避免使用它。

總結(jié)

defer 語句經(jīng)常使用于成對的操作,比如打開和關(guān)閉,連接和斷開,加鎖和解鎖,即便是再復(fù)雜的控制流,資源在任何情況下都能夠正確釋放。

補(bǔ)充:Golang中defer的三個(gè)實(shí)戰(zhàn)要點(diǎn)

前言

Golang中的defer是使用頻次比較高的,能創(chuàng)造出延遲生效特效的一種方式。

defer也有自己的矯情,需要注意的。

本文將從通過代碼的方式來說明defer的三點(diǎn)矯情。

1.defer的生效順序

2.defer與return,函數(shù)返回值之間的順序

3.defer定義和執(zhí)行兩個(gè)步驟,做的事情。

正文

1.defer的生效順序

先說結(jié)論:defer的執(zhí)行順序是倒序執(zhí)行(同入棧先進(jìn)后出)

func main() {
 defer func() {
 fmt.Println("我后出來")
 }()
 defer func() {
 fmt.Println("我先出來")
 }()
}

執(zhí)行后打印出:

我先出來

我后出來

2.defer與return,函數(shù)返回值之間的順序

先說結(jié)論:return最先執(zhí)行->return負(fù)責(zé)將結(jié)果寫入返回值中->接著defer開始執(zhí)行一些收尾工作->最后函數(shù)攜帶當(dāng)前返回值退出

返回值的表達(dá)方式,我們知道根據(jù)是否提前聲明有兩種方式:一種是func test() int 另一種是 func test() (i int),所以兩種情況都來說說

func test() int
func main() {
 fmt.Println("main:", test())
}
func test() int {
 var i int
 defer func() {
 i++
 fmt.Println("defer2的值:", i)
 }()
 defer func() {
 i++
 fmt.Println("defer1的值:", i)
 }()
 return i
}

輸出:

defer1的值: 1

defer2的值: 2

main: 0

詳解:return的時(shí)候已經(jīng)先將返回值給定義下來了,就是0,由于i是在函數(shù)內(nèi)部聲明所以即使在defer中進(jìn)行了++操作,也不會(huì)影響return的時(shí)候做的決定。

func test() (i int)
func main() {
 fmt.Println("main:", test())
}
func test() (i int) {
 defer func() {
 i++
 fmt.Println("defer2的值:", i)
 }()
 defer func() {
 i++
 fmt.Println("defer1的值:", i)
 }()
 return i
}

輸出:

defer1的值: 1

defer2的值: 2

main: 2

詳解:由于返回值提前聲明了,所以在return的時(shí)候決定的返回值還是0,但是后面兩個(gè)defer執(zhí)行后進(jìn)行了兩次++,將i的值變?yōu)?,待defer執(zhí)行完后,函數(shù)將i值進(jìn)行了返回。

3.defer定義和執(zhí)行兩個(gè)步驟,做的事情

先說結(jié)論:會(huì)先將defer后函數(shù)的參數(shù)部分的值(或者地址)給先下來【你可以理解為()里頭的會(huì)先確定】,后面函數(shù)執(zhí)行完,才會(huì)執(zhí)行defer后函數(shù)的{}中的邏輯

func test(i *int) int {
 return *i
}
func main(){
 var i = 1
 // defer定義的時(shí)候test(&i)的值就已經(jīng)定了,是1,后面就不會(huì)變了
 defer fmt.Println("i1 =" , test(&i))
 i++
 // defer定義的時(shí)候test(&i)的值就已經(jīng)定了,是2,后面就不會(huì)變了
 defer fmt.Println("i2 =" , test(&i))
 // defer定義的時(shí)候,i就已經(jīng)確定了是一個(gè)指針類型,地址上的值變了,這里跟著變
 defer func(i *int) {
 fmt.Println("i3 =" , *i)
 }(&i)
 // defer定義的時(shí)候i的值就已經(jīng)定了,是2,后面就不會(huì)變了
 defer func(i int) {
 //defer 在定義的時(shí)候就定了
 fmt.Println("i4 =" , i)
 }(i)
 defer func() {
 // 地址,所以后續(xù)跟著變
 var c = &i
 fmt.Println("i5 =" , *c)
 }()
 
 // 執(zhí)行了 i=11 后才調(diào)用,此時(shí)i值已是11
 defer func() {
 fmt.Println("i6 =" , i)
 }()
 i = 11
}

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教。

相關(guān)文章

  • go語言中線程池的實(shí)現(xiàn)

    go語言中線程池的實(shí)現(xiàn)

    Go語言中并沒有直接類似 Java 線程池的內(nèi)建概念,主要通過goroutine和channel來實(shí)現(xiàn)并發(fā)處理,本文主要介紹了go語言中線程池的實(shí)現(xiàn),具有一定的參考價(jià)值,感興趣的可以了解一下
    2025-04-04
  • golang defer執(zhí)行順序全面詳解

    golang defer執(zhí)行順序全面詳解

    這篇文章主要為大家介紹了golang defer執(zhí)行順序全面詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-09-09
  • 使用Go語言實(shí)現(xiàn)LRU緩存的代碼詳解

    使用Go語言實(shí)現(xiàn)LRU緩存的代碼詳解

    在日常開發(fā)中,緩存是提高系統(tǒng)性能的重要手段,LRU緩存是一種基于“最近最少使用”策略的緩存系統(tǒng),其目的是在空間受限的情況下保留最新、最常用的數(shù)據(jù),本文將詳細(xì)講解如何使用?Go?語言實(shí)現(xiàn)一個(gè)?LRU?緩存,需要的朋友可以參考下
    2024-11-11
  • Golang文件操作之讀取與寫入方法全攻略

    Golang文件操作之讀取與寫入方法全攻略

    本文詳細(xì)介紹了在Go語言中進(jìn)行文件操作的方法,包括文件的創(chuàng)建、打開、讀取、寫入和關(guān)閉等,解析了使用os、bufio和io包進(jìn)行高效文件操作的技巧,并提供了錯(cuò)誤處理與性能優(yōu)化的建議,以幫助開發(fā)者有效管理文件資源并提升應(yīng)用性能,需要的朋友可以參考下
    2024-11-11
  • Golang Map類型的使用(增刪查改)

    Golang Map類型的使用(增刪查改)

    在Go中,map是哈希表的引用,是一種key-value數(shù)據(jù)結(jié)構(gòu),本文主要介紹了Golang Map類型的使用,具有一定的參考價(jià)值,感興趣的可以了解一下
    2024-05-05
  • Go使用context控制協(xié)程取消的實(shí)戰(zhàn)案例

    Go使用context控制協(xié)程取消的實(shí)戰(zhàn)案例

    在并發(fā)編程中,合理地控制協(xié)程的生命周期是保證程序穩(wěn)定性和資源可控使用的關(guān)鍵,Go語言標(biāo)準(zhǔn)庫中的context包正是為了解決這一問題而生,它為我們提供了取消信號、超時(shí)控制、請求作用域的值傳遞等功能,本文將通過一個(gè)實(shí)際案例,演示如何使用context控制協(xié)程的取消
    2025-08-08
  • Go語言中動(dòng)態(tài)調(diào)用不同簽名的函數(shù)的實(shí)現(xiàn)

    Go語言中動(dòng)態(tài)調(diào)用不同簽名的函數(shù)的實(shí)現(xiàn)

    本文主要介紹了Go語言中動(dòng)態(tài)調(diào)用不同簽名的函數(shù)的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2025-05-05
  • Go語言包管理工具dep的安裝與使用

    Go語言包管理工具dep的安裝與使用

    godep是解決包依賴的管理工具,下面這篇文章主要給大家介紹了關(guān)于Go語言包管理工具dep的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2018-07-07
  • Golang如何交叉編譯各個(gè)平臺(tái)的二進(jìn)制文件詳解

    Golang如何交叉編譯各個(gè)平臺(tái)的二進(jìn)制文件詳解

    這篇文章主要給大家介紹了關(guān)于Golang如何交叉編譯各個(gè)平臺(tái)的二進(jìn)制文件的相關(guān)資料,并介紹了golang如何讓編譯生產(chǎn)的二進(jìn)制文件變小,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2018-08-08
  • Go標(biāo)準(zhǔn)容器之Ring的使用說明

    Go標(biāo)準(zhǔn)容器之Ring的使用說明

    這篇文章主要介紹了Go標(biāo)準(zhǔn)容器之Ring的使用說明,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2021-05-05

最新評論