日本综合一区二区|亚洲中文天堂综合|日韩欧美自拍一区|男女精品天堂一区|欧美自拍第6页亚洲成人精品一区|亚洲黄色天堂一区二区成人|超碰91偷拍第一页|日韩av夜夜嗨中文字幕|久久蜜综合视频官网|精美人妻一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
Go語言中使用Defer幾個場景

關(guān)于 defer 的詳細介紹請參考: Defer, Panic, and Recover .

我們注重客戶提出的每個要求,我們充分考慮每一個細節(jié),我們積極的做好網(wǎng)站制作、網(wǎng)站設(shè)計服務(wù),我們努力開拓更好的視野,通過不懈的努力,創(chuàng)新互聯(lián)贏得了業(yè)內(nèi)的良好聲譽,這一切,也不斷的激勵著我們更好的服務(wù)客戶。 主要業(yè)務(wù):網(wǎng)站建設(shè),網(wǎng)站制作,網(wǎng)站設(shè)計,小程序定制開發(fā),網(wǎng)站開發(fā),技術(shù)開發(fā)實力,DIV+CSS,PHP及ASP,ASP.Net,SQL數(shù)據(jù)庫的技術(shù)開發(fā)工程師。

C++ 中模擬的 defer 實現(xiàn)請參考: C++版的defer語句

1. 簡化資源的回收

這是最常見的 defer 用法. 比如:

 
 
 
  1. mu.Lock()  
  2. defer mu.Unlock() 

當(dāng)然, defer 也有一定的開銷, 也有為了節(jié)省性能而回避使用的 defer 的:

 
 
 
  1. mu.Lock()  
  2. count++  
  3. mu.Unlock() 

從簡化資源的釋放角度看, defer 類似一個語法糖, 好像不是必須的.

2. panic異常的捕獲

defer 除了用于簡化資源的釋放外, 還是Go語言異常框架的一個組成部分.

Go語言中, panic用于拋出異常, recover用于捕獲異常. recover只能在defer語句中使用, 直接調(diào)用recover是無效的.

比如:

 
 
 
  1. func main() {  
  2.     f()  
  3.     fmt.Println("Returned normally from f.")  
  4. }  
  5.  
  6. func f() {  
  7.     defer func() {  
  8.         if r := recover(); r != nil {  
  9.             fmt.Println("Recovered in f", r)  
  10.         }  
  11.     }()  
  12.     fmt.Println("Calling g.")  
  13.     g()  
  14.     fmt.Println("Returned normally from g.")  
  15. }  
  16.  
  17. func g() {  
  18.     panic("ERROR")  

因此, 如果要捕獲Go語言中函數(shù)的異常, 就離不開defer語句了.

3. 修改返回值

defer 除了用于配合 recover, 用于捕獲 panic 異常外, 還可以用于在 return 之后修改函數(shù)的返回值.

比如:

 
 
 
  1. func doubleSum(a, b int) (sum int) {  
  2.     defer func() {  
  3.         sum *= 2 
  4.     }()  
  5.     sum = a + b  

當(dāng)然, 這個特性應(yīng)該只是 defer 的副作用, 具體在什么場景使用就要由開發(fā)者自己決定了.

4. 安全的回收資源

前面第一點提到, defer 最常見的用法是簡化資源的回收. 而且, 從資源回收角度看, defer 只是一個語法糖.

其實, 也不完全是這樣, 特別是在涉及到第二點提到的panic異常等因素導(dǎo)致goroutine提前退出時.

比如, 有一個線程安全的slice修改函數(shù), 為了性能沒有使用defer語句:

 
 
 
  1. func set(mu *sync.Mutex, arr []int, i, v int) {  
  2.     mu.Lock()  
  3.     arr[i] = v  
  4.     mu.Unlock()  

但是, 如果 i >= len(arr)的話, runtime就會拋出切片越界的異常(這里只是舉例, 實際開發(fā)中不應(yīng)該出現(xiàn)切片越界異常). 這樣的話, mu.Unlock() 就沒有機會被執(zhí)行了.

如果用defer的話, 即使出現(xiàn)異常也能保證mu.Unlock()被調(diào)用:

 
 
 
  1. func set(mu *sync.Mutex, arr []int, i, v int) {  
  2.     mu.Lock()  
  3.     defer mu.Unlock()  
  4.     arr[i] = v  

當(dāng)然, Go語言約定異常不會跨越package邊界. 因此, 調(diào)用一般函數(shù)的時候不用擔(dān)心goroutine異常退出的情況.

不過對于一些比較特殊的package, 比如go test依賴的testing包, 包中的t.Fatal就是依賴了Go中類似異常的特性(準確的說是調(diào)用了runtime.Goexit()).

比如有以下的測試函數(shù)(詳情請參考Issue5746):

 
 
 
  1. func TestFailed(t *testing.T) {  
  2.     var wg sync.WaitGroup  
  3.     for i := 0; i < 2; i++ {  
  4.         wg.Add(1)  
  5.         go func(id int) {  
  6.             // defer wg.Done()  
  7.             t.Fatalf("TestFailed: id = %v\n", id)  
  8.             wg.Done()  
  9.         }(i)  
  10.     }  
  11.     wg.Wait()  

當(dāng)測試失敗的時候, wg.Done()將沒有機會執(zhí)行, 最終導(dǎo)致wg.Wait()死鎖.

對于這個例子, 安全的做法是使用defer語句保證wg.Done()始終會被執(zhí)行.

原文鏈接:http://my.oschina.net/chai2010/blog/140065


名稱欄目:Go語言中使用Defer幾個場景
地址分享:http://www.dlmjj.cn/article/coegoce.html