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

Golang之defer 延遲調用操作

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

前言

defer語句被用于預定對一個函數(shù)的調用。我們把這類被defer語句調用的函數(shù)稱為延遲函數(shù)。而defer 延遲語句在其他編程語言里好像沒有見到。應該是屬于 Go 語言里的獨有的關鍵字。但用法類似于面向對象編程語言 Java 和 C# 的 finally 語句塊。

下面對defer進行介紹。

defer特性

1. 關鍵字 defer 用于注冊延遲調用。

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

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

1.延遲調用

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

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

編譯運行:

2.defer 與 return 孰先孰后

defer 和 return 到底是哪個先調用?先看看例子:

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 )

編譯運行:

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

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

重點在第三行,為什么輸出的是 go ?

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

3.多個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)
}

編譯輸出:

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

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ù)“壓?!?,函數(shù)參數(shù)會被拷貝下來;當外層函數(shù)(非代碼塊,如一個for循環(huán))退出時,defer函數(shù)按照定義的逆序執(zhí)行;如果defer執(zhí)行的函數(shù)為nil, 那么會在最終調用函數(shù)的產生panic.

為什么需要defer?

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

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

defer用途

1. 關閉文件句柄

2. 鎖資源釋放

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

defer的使用其實非常簡單,來看看一個簡單用途:

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語句關閉文件。這樣,在函數(shù)結束之前,會自動執(zhí)行defer后面的語句來關閉文件。

當然,defer會有小小地延遲,對時間要求特別特別特別高的程序,可以避免使用它。

總結

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

補充:Golang中defer的三個實戰(zhàn)要點

前言

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

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

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

1.defer的生效順序

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

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

正文

1.defer的生效順序

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

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

執(zhí)行后打印出:

我先出來

我后出來

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

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

返回值的表達方式,我們知道根據(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的時候已經(jīng)先將返回值給定義下來了,就是0,由于i是在函數(shù)內部聲明所以即使在defer中進行了++操作,也不會影響return的時候做的決定。

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的時候決定的返回值還是0,但是后面兩個defer執(zhí)行后進行了兩次++,將i的值變?yōu)?,待defer執(zhí)行完后,函數(shù)將i值進行了返回。

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

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

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

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

相關文章

  • Golang中錯誤處理機制詳解

    Golang中錯誤處理機制詳解

    平時在項目開發(fā)過程中少不了對錯誤的處理,一個好用的系統(tǒng)首先要確保其健壯性,不能經(jīng)常發(fā)生錯誤就卡死之類的情況,為了讓我們的程序更加健壯,我們就需要知道golang里的錯誤處理機制是怎么樣的,這篇文章帶大家一起學習,需要的朋友跟著小編一起來看看吧
    2024-05-05
  • Golang實踐筆錄之讀取yaml配置文件

    Golang實踐筆錄之讀取yaml配置文件

    YAML是YAML?Ain't?a?Markup?Language的縮寫,YAML不是一種標記語言,相比JSON格式的方便,這篇文章主要給大家介紹了關于Golang實踐筆錄之讀取yaml配置文件的相關資料,文中通過代碼介紹的非常詳細,需要的朋友可以參考下
    2024-01-01
  • Go Resiliency庫中timeout實現(xiàn)原理及源碼解析

    Go Resiliency庫中timeout實現(xiàn)原理及源碼解析

    Go-Resiliency庫中的timeout是一種基于協(xié)程的超時機制,通過創(chuàng)建協(xié)程來執(zhí)行任務并設置超時時間,若任務執(zhí)行時間超時則中止協(xié)程并返回錯誤,需要詳細了解可以參考下文
    2023-05-05
  • 淺析Go語言中的同步與異步處理

    淺析Go語言中的同步與異步處理

    在開發(fā)過程中,當需要同時處理多個操作時,開發(fā)者經(jīng)常面臨同步和異步兩種處理方式的選擇,下面小編就來和大家詳細介紹一下Go語言中的同步與異步處理吧
    2023-11-11
  • 一文詳解golang通過io包進行文件讀寫

    一文詳解golang通過io包進行文件讀寫

    這篇文章主要介紹了golang通過io包進行文件讀寫文中有詳細的代碼示例。對學習或工資有很好的幫助,需要的小伙伴可以參考閱讀一下
    2023-04-04
  • Golang中零切片、空切片、nil切片

    Golang中零切片、空切片、nil切片

    切片是最常用的數(shù)據(jù)結構之一,但許多開發(fā)者對零切片、空切片和nil切片的概念模糊不清,本文主要介紹了這三種的區(qū)別,具有一定的參考價值,感興趣的可以了解一下
    2025-06-06
  • Golang自動追蹤GitHub上熱門AI項目

    Golang自動追蹤GitHub上熱門AI項目

    這篇文章主要為大家介紹了Golang自動追蹤GitHub上熱門AI項目,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-12-12
  • golang中為什么Response.Body需要被關閉詳解

    golang中為什么Response.Body需要被關閉詳解

    這篇文章主要給大家介紹了關于golang中為什么Response.Body需要被關閉的相關資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2018-08-08
  • golang如何使用struct的tag屬性的詳細介紹

    golang如何使用struct的tag屬性的詳細介紹

    這篇文章主要介紹了golang如何使用struct的tag屬性的詳細介紹,從例子說起,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-11-11
  • Go語言模型:string的底層數(shù)據(jù)結構與高效操作詳解

    Go語言模型:string的底層數(shù)據(jù)結構與高效操作詳解

    這篇文章主要介紹了Go語言模型:string的底層數(shù)據(jù)結構與高效操作詳解,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-12-12

最新評論

望谟县| 故城县| 秦皇岛市| 大洼县| 瑞安市| 湘潭县| 乌鲁木齐市| 醴陵市| 香格里拉县| 旬阳县| 沙田区| 油尖旺区| 建平县| 临夏县| 策勒县| 虞城县| 尤溪县| 长沙市| 肥东县| 长汀县| 昌平区| 喀喇| 丹巴县| 玉林市| 鄄城县| 昌图县| 泾阳县| 襄城县| 马边| 石台县| 泾阳县| 三河市| 新建县| 南岸区| 南开区| 宿迁市| 奉新县| 罗定市| 育儿| 涟水县| 广宁县|