1. 程式人生 > >go語言defer使用

go語言defer使用

defer

Go語言中有種不錯的設計,即延遲(defer)語句,你可以在函式中新增多個defer語句。當函式執行到最後時,這些defer語句會按照逆序執行,最後該函式返回。特別是當你在進行一些開啟資源的操作時,遇到錯誤需要提前返回,在返回前你需要關閉相應的資源,不然很容易造成資源洩露等問題。如下程式碼所示,我們一般寫開啟一個資源是這樣操作的:

func ReadWrite() bool {
    file.Open("file")
// 做一些工作
    if failureX {
        file.Close()
        return false
    }

    if failureY {
        file.Close()
        return false
    }

    file.Close()
    return true
}

我們看到上面有很多重複的程式碼,Go的defer有效解決了這個問題。使用它後,不但程式碼量減少了很多,而且程式變得更優雅。在defer後指定的函式會在函式退出前呼叫。

func ReadWrite() bool {
    file.Open("file")
    defer file.Close()
    if failureX {
        return false
    }
    if failureY {
        return false
    }
    return true
}

如果有很多呼叫defer,那麼defer是採用後進先出模式,所以如下程式碼會輸出4 3 2 1 0

for i := 0; i < 5; i++ {
    defer fmt.Printf("%d ", i)
}

defer 給我的第一印象就是,類似java中的

try {

}finally {

}

我目前的理解就是,在函式塊中使用defer,就是函式對應的有一個棧空間,先進後出。需要函式結束後呼叫棧,來出發defer操作。

如果,一個物件的建立,很消耗記憶體,需要及時關閉,defer無法像try finnaly哪樣準確。

package main

import "fmt"
import "time"

type User struct {
        username string
}

func (this *User) Close() {
        fmt.Println(this.username, "Closed !!!")
}

func main() {
        u1 := &User{"jack"}
        defer u1.Close()
        u2 := &User{"lily"}
        defer u2.Close()

        time.Sleep(10 * time.Second)

        fmt.Println("Done !")

}
[
[email protected]
goroutine]$


[[email protected] goroutine]$ go run deferTest1.go
Done !
lily Closed !!!
jack Closed !!!
[[email protected] goroutine]$

實際上,執行緒Sleep的10秒,u1,和u2早就可以Close()了,但卻需要依賴main()函式的結束,才能defer執行。

那麼嘗試給defer新增內部程式碼區:

package main

import "fmt"
import "time"

type User struct {
        username string
}

func (this *User) Close() {
        fmt.Println(this.username, "Closed !!!")
}

func main() {
        {
                // 即便加了程式碼快範圍,依舊也要主函式體結束才執行defer
                u1 := &User{"jack"}
                defer u1.Close()
        }
        u2 := &User{"lily"}
        defer u2.Close()

        time.Sleep(10 * time.Second)

        fmt.Println("Done !")

}

Done !
lily Closed !!!
jack Closed !!!
[[email protected] goroutine]$

依舊defer的執行在Done!後。那麼如何才能達到try finally 哪樣準確的Close呢?

package main

import "fmt"
import "time"

type User struct {
        username string
}

func (this *User) Close() {
        fmt.Println(this.username, "Closed !!!")
}

func main() {
        u1 := &User{"jack"}
        f(u1) // 這樣的方式,u1才會不依賴main函式的執行

        // 這樣的方式,u2也不會依賴main函式的執行
        u2 := &User{"lily"}
        // m := func() {
        //         defer u2.Close()
        //         // u2 do somthing
        // }
        // m()
        func() {
                 defer u2.Close()
                 // u2 do somthing
        }()
time.Sleep(10 * time.Second) fmt.Println("Done !")}func f(u *User) { defer u.Close() // u1 do gomething}
[[email protected] goroutine]$ go run deferTest3.go
jack Closed !!!
lily Closed !!!
Done !

這樣的使用方式,視乎不太合理,但卻有存在的必要性。大多數情況下,可以用於 u1,u2  之類非常消耗記憶體,或者cpu,其後執行時間過程且沒有太多關聯的情況。既保留了defer的功能特性,也滿足範圍精確控制的條件!

相關推薦

Go語言-defer的使用

return println 結果 nil 出現異常 ror () 使用 package defer 不管程序是否出現異常,均在函數退出時候,自動執行相關代碼 實戰 實例1 package main import ( "fmt" ) func main() {

go語言defer使用

defer Go語言中有種不錯的設計,即延遲(defer)語句,你可以在函式中新增多個defer語句。當函式執行到最後時,這些defer語句會按照逆序執行,最後該函式返回。特別是當你在進行一些開啟資源的操作時,遇到錯誤需要提前返回,在返回前你需要關閉相應的資源,不然很容

探究 Go 語言 defer 語句的三種機制

Golang 的 1.13 版本 與 1.14 版本對 defer 進行了兩次優化,使得 defer 的效能開銷在大部分場景下都得到大幅降低,其中到底經歷了什麼原理? 這是因為這兩個版本對 defer 各加入了一項新的機制,使得 defer 語句在編譯時,編譯器會根據不同版本與情況,對每個 defer 選擇不

Go語言defer分析

什麼是defer? defer語句是專門在函式結束以後做一些清理工作的。我們先舉一個例子來更好的理解,現在有一個函式,它的作用是把一個檔案內容拷貝到另一個檔案。 func CopyFile(dstName string, srcName string) (written int64, err error) {

Go語言defer

defer關鍵字 defer和go一樣都是Go語言提供的關鍵字. defer用於資源的釋放, 會在函式返回之前進行呼叫. 要使用好defer最重要的是要理解return執行過程: 先給返回值賦值, 然後呼叫defer表示式, 最後才是返回到呼叫函式中. 理解了這句話, 關於defe

go語言中使用defer、panic、recover處理異常

baidu 繼續 spa hello http tid 處理流 dex integer go語言中的異常處理,沒有try...catch等,而是使用defer、panic、recover來處理異常。 1、首先,panic 是用來表示非常嚴重的不可恢復的錯誤的。在Go語

Go語言異常處理defer\panic\recover

Go語言異常處理defer\panic\recover Go語言追求簡潔優雅,所以,Go語言不支援傳統的 try…catch…f

Go語言學習——徹底弄懂return和defer的微妙關係

疑問   前面在函式篇裡介紹了Go語言的函式是支援多返回值的。   只要在函式體內,對返回值賦值,最後加上return就可以返回所有的返回值。   最近在寫程式碼的時候經常遇到在return後,還要在defer裡面做一些收尾工作,比如事務的提交或回滾。所以想弄清楚這個return和defer到底是什麼關

Go語言之嵌入類型

go 類型 嵌入類型,或者嵌套類型,這是一種可以把已有的類型聲明在新的類型裏的一種方式,這種功能對代碼復用非常重要。在其他語言中,有繼承可以做同樣的事情,但是在Go語言中,沒有繼承的概念。Go提倡的代碼復用的方式是組合,所以這也是嵌入類型的意義所在。組合而不是繼承,所以Go才會更靈活。type Rea

go語言的優點

程序編寫 執行文件 語言培訓 多線程 老男孩 老男孩教育go語言培訓是國內首家go語言培訓機構,主講老師是小米架構資深架構師,有多年go開發經驗。小編現將go語言優點整理如下,希望能幫到你們 1.部署簡單Go 編譯生成的是一個靜態可執行文件,除了 glibc 外沒有其他外部依賴。這讓部署變

go語言筆記——append是內置的函數!!!new是一個函數!!!調試可以使用閉包,本質上是print調試,尼瑪!

... -c map blob 名稱 ebo bsp 處理機制 它的 內置函數 Go 語言擁有一些不需要進行導入操作就可以使用的內置函數。它們有時可以針對不同的類型進行操作,例如:len、cap 和 append,或必須用於系統級的操作,例如:panic。因此,它們需要直接

go語言筆記——切片函數常見操作,增刪改查和搜索、排序

通過 學習 strings 完整 官方文檔 二分 func fun 必須 7.6.6 搜索及排序切片和數組 標準庫提供了 sort 包來實現常見的搜索和排序操作。您可以使用 sort 包中的函數 func Ints(a []int) 來實現對 int 類型的切片排序。例如

go語言筆記——map map 默認是無序的,不管是按照 key 還是按照 value 默認都不排序

pcr 錯誤 固定 pre text 輸出結果 示例 operation frequency 示例 8.1 make_maps.go package main import "fmt" func main() { var mapLit map[string]int

GO語言 --socket.io

broadcast logfile hub println ogg sta out his ror socket.io是對websocket的封裝以及擴展, 可以跨平臺使用, 具體可看官網.. GO語言實現: package main import (

Go語言之標誌符可見性

goGo的標誌符,這個翻譯覺得怪怪的,不過還是按這個起了標題,可以理解為Go的變量、類型、字段等。這裏的可見性,也就是說那些方法、函數、類型或者變量字段的可見性。比如哪些方法不想讓另外一個包訪問,我們就可以把它們聲明為非公開的;如果需要被另外一個包訪問,就可以聲明為公開的,和Java語言裏的作用域類似。在Go

CentOS6.8配置GO語言開發環境

應用程序 編程語言 處理器 谷歌 export 導讀Go語言是谷歌2009發布的第二款開源編程語言,Go語言專門針對多處理器系統應用程序的編程進行了優化,使用Go編譯的程序可以媲美C或C++代碼的速度,而且更加安全、支持並行進程。 鑒於越來越多的開源項目都采用Go為開發語言,本文介紹Lin

奇妙的go語言(開始篇)

使用 turn row list strong input put content nds 【 聲明:版權全部。歡迎轉載,請勿用於商業用途。 聯系信箱:feixiaoxing @163.com】 從前接觸腳本語言不多,可是自從遇到go之後,就開始慢慢喜歡上了這個腳

go語言sync包的學習(Mutex、WaitGroup、Cond)

pri lee 拷貝 light 等待 runt broadcast 計算 混亂 package main; import ( "fmt" "sync" "runtime" "time" ) //加鎖,註意鎖要以指針的形式傳進來,不然只是拷

Go語言之Doc 文檔

go doc 對於協作開發或者代碼共享來說,文檔是一個可以幫助開發者快速了解以及使用這些代碼的一個教程,文檔越全面、越詳細,入門越快,效率也會更高。在Go語言中,Go為我們提供了快速生成文檔以及查看文檔的工具,讓我們可以很容易地編寫查看文檔。Go提供了兩種查看文檔的方式:一種是使用go doc命令在終

go語言time包的學習(Time,Location,Duration,Timer,Ticker)

after 當前時間 ++ 語言 pre before hour 字符 asi package main; import ( "time" "fmt" ) func main() { //time.Time代表一個納秒精度的時間點 var