GO語言————6.4 defer 和追蹤
6.4 defer 和追蹤
關鍵字 defer 允許我們推遲到函式返回之前(或任意位置執行 return
語句之後)一刻才執行某個語句或函式(為什麼要在返回之後才執行這些語句?因為 return
語句同樣可以包含一些操作,而不是單純地返回某個值)。
關鍵字 defer 的用法類似於物件導向程式語言 Java 和 C# 的 finally
語句塊,它一般用於釋放某些已分配的資源。
示例 6.8 defer.go:
package main
import "fmt"
func main() {
function1()
}
func function1() {
fmt.Printf("In function1 at the top\n")
defer function2()
fmt.Printf("In function1 at the bottom!\n")
}
func function2() {
fmt.Printf("Function2: Deferred until the end of the calling function!")
}
輸出:
In Function1 at the top
In Function1 at the bottom!
Function2: Deferred until the end of the calling function!
請將 defer 關鍵字去掉並對比輸出結果。
使用 defer 的語句同樣可以接受引數,下面這個例子就會在執行 defer 語句時列印 0
:
func a() {
i := 0
defer fmt.Println(i)
i++
return
}
當有多個 defer 行為被註冊時,它們會以逆序執行(類似棧,即後進先出):
func f() {
for i := 0; i < 5; i++ {
defer fmt.Printf("%d ", i)
}
}
上面的程式碼將會輸出:4 3 2 1 0
。
關鍵字 defer 允許我們進行一些函式執行完成後的收尾工作,例如:
- 關閉檔案流 (詳見 第 12.2 節)
// open a file
defer file.Close()
- 解鎖一個加鎖的資源 (詳見 第 9.3 節)
mu.Lock()
defer mu.Unlock()
- 列印最終報告
printHeader()
defer printFooter()
- 關閉資料庫連結
// open a database connection
defer disconnectFromDB()
合理使用 defer 語句能夠使得程式碼更加簡潔。
以下程式碼模擬了上面描述的第 4 種情況:
package main
import "fmt"
func main() {
doDBOperations()
}
func connectToDB() {
fmt.Println("ok, connected to db")
}
func disconnectFromDB() {
fmt.Println("ok, disconnected from db")
}
func doDBOperations() {
connectToDB()
fmt.Println("Defering the database disconnect.")
defer disconnectFromDB() //function called here with defer
fmt.Println("Doing some DB operations ...")
fmt.Println("Oops! some crash or network error ...")
fmt.Println("Returning from function here!")
return //terminate the program
// deferred function executed here just before actually returning, even if
// there is a return or abnormal termination before
}
輸出:
ok, connected to db
Defering the database disconnect.
Doing some DB operations ...
Oops! some crash or network error ...
Returning from function here!
ok, disconnected from db
使用 defer 語句實現程式碼追蹤
一個基礎但十分實用的實現程式碼執行追蹤的方案就是在進入和離開某個函式列印相關的訊息,即可以提煉為下面兩個函式:
func trace(s string) { fmt.Println("entering:", s) }
func untrace(s string) { fmt.Println("leaving:", s) }
以下程式碼展示了何時呼叫這兩個函式:
示例 6.10 defer_tracing.go:
package main
import "fmt"
func trace(s string) { fmt.Println("entering:", s) }
func untrace(s string) { fmt.Println("leaving:", s) }
func a() {
trace("a")
defer untrace("a")
fmt.Println("in a")
}
func b() {
trace("b")
defer untrace("b")
fmt.Println("in b")
a()
}
func main() {
b()
}
輸出:
entering: b
in b
entering: a
in a
leaving: a
leaving: b
上面的程式碼還可以修改為更加簡便的版本(示例 6.11 defer_tracing2.go):
package main
import "fmt"
func trace(s string) string {
fmt.Println("entering:", s)
return s
}
func un(s string) {
fmt.Println("leaving:", s)
}
func a() {
defer un(trace("a"))
fmt.Println("in a")
}
func b() {
defer un(trace("b"))
fmt.Println("in b")
a()
}
func main() {
b()
}
使用 defer 語句來記錄函式的引數與返回值
下面的程式碼展示了另一種在除錯時使用 defer 語句的手法(示例 6.12 defer_logvalues.go):
package main
import (
"io"
"log"
)
func func1(s string) (n int, err error) {
defer func() {
log.Printf("func1(%q) = %d, %v", s, n, err)
}()
return 7, io.EOF
}
func main() {
func1("Go")
}
相關文章
- Linux 核心網路包路徑追蹤利器 skbtracer,Go 語言版本LinuxGo
- 為忙碌開發者準備的 Go 語言效能分析、追蹤和可觀測性指南Go
- Rust 語言的全鏈路追蹤庫 tracingRust
- go的鏈路追蹤Go
- 如何追蹤Go動態Go
- Go 鏈路追蹤入門 OpentelemetryGo
- Go 語言 nil 和介面Go
- Go語言中defer的一些坑Go
- Go 語言中 defer 使用時有哪些陷阱?Go
- Go語言————1、初識GO語言Go
- gRPC的請求追蹤神器 go tool traceRPCGo
- Go - 實現專案內鏈路追蹤Go
- Oracle執行語句跟蹤 使用sql trace實現語句追蹤OracleSQL
- Go基礎系列:defer、panic和recoverGo
- go-kit微服務:服務鏈路追蹤Go微服務
- (16)go-micro微服務jaeger鏈路追蹤Go微服務
- Go - 實現專案內鏈路追蹤(二)Go
- Jaeger Client Go 鏈路追蹤|入門詳解clientGo
- GO語言————4.7 strings和strconv 包Go
- GO語言————4.8 時間和日期Go
- Go 語言指標符號 *和&Go指標符號
- Go 語言 結構體和方法Go結構體
- 帶讀 |《Go in Action》(中文:Go語言實戰) 語法和語言結構概覽(三)Go
- 帶讀 |《Go in Action》(中文:Go語言實戰)語法和語言結構概覽 (二)Go
- GO語言————2、GO語言環境安裝Go
- Go 中的Defer,Panic 和 Recover 控制流Go
- Go語言中用於錯誤處理的Defer、Panic和Recover - Sachin KarveGo
- go-zero的全鏈路追蹤與超時Go
- 【Go語言入門系列】(八)Go語言是不是面嚮物件語言?Go物件
- Go_go語言初探Go
- GO語言————4.2 Go程式的基本結構和要素Go
- GO語言—————7.1 宣告和初始化Go
- go語言簽發和驗證licenseGo
- go語言學習-安裝和配置Go
- Java和Go語言二選一,選擇哪門語言好?JavaGo
- Go語言mapGo
- go 語言切片Go
- go 語言常量Go