go語言defer使用 .

來源:互聯網
上載者:User
這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。

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哪樣準確。

[plain] view plaincopyprint?
  1. package main  
  2.   
  3. import "fmt"  
  4. import "time"  
  5.   
  6. type User struct {  
  7.         username string  
  8. }  
  9.   
  10. func (this *User) Close() {  
  11.         fmt.Println(this.username, "Closed !!!")  
  12. }  
  13.   
  14. func main() {  
  15.         u1 := &User{"jack"}  
  16.         defer u1.Close()  
  17.         u2 := &User{"lily"}  
  18.         defer u2.Close()  
  19.   
  20.         time.Sleep(10 * time.Second)  
  21.   
  22.         fmt.Println("Done !")  
  23.   
  24. }  
  25. [vicky@localhost goroutine]$  
package mainimport "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 !")}[vicky@localhost goroutine]$


[vicky@localhost goroutine]$ go run deferTest1.go
Done !
lily Closed !!!
jack Closed !!!
[vicky@localhost goroutine]$


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

那麼嘗試給defer添加內部代碼區:


[plain] view plaincopyprint?
  1. package main  
  2.   
  3. import "fmt"  
  4. import "time"  
  5.   
  6. type User struct {  
  7.         username string  
  8. }  
  9.   
  10. func (this *User) Close() {  
  11.         fmt.Println(this.username, "Closed !!!")  
  12. }  
  13.   
  14. func main() {  
  15.         {  
  16.                 // 即便加了代碼快範圍,依舊也要主函數體結束才執行defer  
  17.                 u1 := &User{"jack"}  
  18.                 defer u1.Close()  
  19.         }  
  20.         u2 := &User{"lily"}  
  21.         defer u2.Close()  
  22.   
  23.         time.Sleep(10 * time.Second)  
  24.   
  25.         fmt.Println("Done !")  
  26.   
  27. }  
package mainimport "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 !!!
[vicky@localhost goroutine]$


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

[plain] view plaincopyprint?
  1. package main  
  2.   
  3. import "fmt"  
  4. import "time"  
  5.   
  6. type User struct {  
  7.         username string  
  8. }  
  9.   
  10. func (this *User) Close() {  
  11.         fmt.Println(this.username, "Closed !!!")  
  12. }  
  13.   
  14. func main() {  
  15.         u1 := &User{"jack"}  
  16.         f(u1) // 這樣的方式,u1才會不依賴main函數的執行  
  17.   
  18.         // 這樣的方式,u2也不會依賴main函數的執行  
  19.         u2 := &User{"lily"}  
  20.         // m := func() {  
  21.         //         defer u2.Close()  
  22.         //         // u2 do somthing  
  23.         // }  
  24.         // m()<PRE class=plain name="code">        func() {  
  25.                  defer u2.Close()  
  26.                  // u2 do somthing  
  27.         }()</PRE>        time.Sleep(10 * time.Second)        fmt.Println("Done !")}func f(u *User) {        defer u.Close()        // u1 do gomething}  
package mainimport "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()<div class="dp-highlighter bg_plain"><div class="bar"><div class="tools"><strong>[plain]</strong> <a target=_blank class="ViewSource" title="view plain" href="http://blog.csdn.net/eclipser1987/article/details/12089271#">view plain</a><a target=_blank class="CopyToClipboard" title="copy" href="http://blog.csdn.net/eclipser1987/article/details/12089271#">copy</a><a target=_blank class="PrintSource" title="print" href="http://blog.csdn.net/eclipser1987/article/details/12089271#">print</a><a target=_blank class="About" title="?" href="http://blog.csdn.net/eclipser1987/article/details/12089271#">?</a><a target=_blank href="http://blog.csdn.net/eclipser1987/article/details/12089271"></a></div></div><ol><li class="alt"><span><span>func() {  </span></span></li><li><span>         defer u2.Close()  </span></li><li class="alt"><span>         // u2 do somthing  </span></li><li><span>}()  </span></li></ol></div><pre style="DISPLAY: none" class="plain" name="code">        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}


[vicky@localhost goroutine]$ go run deferTest3.go
jack Closed !!!
lily Closed !!!
Done !


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

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.