欧美亚洲中文,在线国自产视频,欧洲一区在线观看视频,亚洲综合中文字幕在线观看

      1. <dfn id="rfwes"></dfn>
          <object id="rfwes"></object>
        1. 站長資訊網(wǎng)
          最全最豐富的資訊網(wǎng)站

          在Go中什么是defer?怎么用?

          本文由go語言教程欄目給大家介紹,主題是關(guān)于go defer的學(xué)習(xí)使用,希望對需要的朋友有所幫助!

          什么是defer?

          在Go中,一個函數(shù)調(diào)用可以跟在一個defer關(guān)鍵字后面,形成一個延遲函數(shù)調(diào)用。
          當(dāng)一個函數(shù)調(diào)用被延遲后,它不會立即被執(zhí)行。它將被推入由當(dāng)前協(xié)程維護(hù)的一個延遲調(diào)用堆棧。 當(dāng)一個函數(shù)調(diào)用(可能是也可能不是一個延遲調(diào)用)返回并進(jìn)入它的退出階段后,所有在此函數(shù)調(diào)用中已經(jīng)被推入的延遲調(diào)用將被按照它們被推入堆棧的順序逆序執(zhí)行。 當(dāng)所有這些延遲調(diào)用執(zhí)行完畢后,此函數(shù)調(diào)用也就真正退出了。
          舉個簡單的例子:

          package mainimport "fmt"func sum(a, b int) {     defer fmt.Println("sum函數(shù)即將返回")     defer fmt.Println("sum函數(shù)finished")     fmt.Printf("參數(shù)a=%v,參數(shù)b=%v,兩數(shù)之和為%vn", a, b, a+b)}func main() {     sum(1, 2)}

          output:

          參數(shù)a=1,參數(shù)b=2,兩數(shù)之和為3 sum函數(shù)finished sum函數(shù)即將返回

          事實上,每個協(xié)程維護(hù)著兩個調(diào)用堆棧。

          • 一個是正常的函數(shù)調(diào)用堆棧。在此堆棧中,相鄰的兩個調(diào)用存在著調(diào)用關(guān)系。晚進(jìn)入堆棧的調(diào)用被早進(jìn)入堆棧的調(diào)用所調(diào)用。 此堆棧中最早被推入的調(diào)用是對應(yīng)協(xié)程的啟動調(diào)用。
          • 另一個堆棧是上面提到的延遲調(diào)用堆棧。處于延遲調(diào)用堆棧中的任意兩個調(diào)用之間不存在調(diào)用關(guān)系。

          defer函數(shù)參數(shù)估值

          • 對于一個延遲函數(shù)調(diào)用,它的實參是在此調(diào)用被推入延遲調(diào)用堆棧的時候被估值的。
          • 一個匿名函數(shù)體內(nèi)的表達(dá)式是在此函數(shù)被執(zhí)行的時候才會被逐個估值的,不管此函數(shù)是被普通調(diào)用還是延遲調(diào)用。
            例子1:
          package mainimport  "fmt"func  Print(a int) {fmt.Println("defer函數(shù)中a的值=", a)}func  main() {a := 10defer  Print(a)a = 1000fmt.Println("a的值=", a)}

          output:

          a的值= 1000 defer函數(shù)中a的值= 10

          defer Print(a) 被加入到延遲調(diào)用堆棧的時候,a 的值是5,故defer Print(a) 輸出的結(jié)果為5
          例子2:

          package mainimport "fmt"func main() {     func() {         for i := 0; i < 3; i++ {             defer fmt.Println("a=", i)         }     }()      fmt.Println()     func() {         for i := 0; i < 3; i++ {             defer func() {                 fmt.Println("b=", i)             }()         }     }()}

          output:

          a= 2 a= 1 a= 0  b= 3 b= 3 b= 3

          第一個匿名函數(shù)循環(huán)中的 i 是在 fmt.Println函數(shù)調(diào)用被推入延遲調(diào)用堆棧的時候估的值,因此輸出結(jié)果是 2,1,0 , 第二個匿名函數(shù)中的 i 是匿名函數(shù)調(diào)用退出階段估的值(此時 i 已經(jīng)變成3了),故結(jié)果輸出:3,3,3。
          其實對第二個匿名函數(shù)調(diào)用略加修改,就能使它輸出和匿名函數(shù)一相同的結(jié)果:

          package mainimport "fmt"func main() {     func() {         for i := 0; i < 3; i++ {             defer fmt.Println("a=", i)         }     }()      fmt.Println()     func() {         for i := 0; i < 3; i++ {             defer func(i int) {                 fmt.Println("b=", i)             }(i)         }     }()}

          output:

          a= 2 a= 1 a= 0  b= 2 b= 1 b= 0

          恐慌(panic)和恢復(fù)(defer + recover)

          Go不支持異常拋出和捕獲,而是推薦使用返回值顯式返回錯誤。 不過,Go支持一套和異常拋出/捕獲類似的機(jī)制。此機(jī)制稱為恐慌/恢復(fù)(panic/recover)機(jī)制。

          我們可以調(diào)用內(nèi)置函數(shù)panic來產(chǎn)生一個恐慌以使當(dāng)前協(xié)程進(jìn)入恐慌狀況。

          進(jìn)入恐慌狀況是另一種使當(dāng)前函數(shù)調(diào)用開始返回的途徑。 一旦一個函數(shù)調(diào)用產(chǎn)生一個恐慌,此函數(shù)調(diào)用將立即進(jìn)入它的退出階段,在此函數(shù)調(diào)用中被推入堆棧的延遲調(diào)用將按照它們被推入的順序逆序執(zhí)行。

          通過在一個延遲函數(shù)調(diào)用之中調(diào)用內(nèi)置函數(shù)recover,當(dāng)前協(xié)程中的一個恐慌可以被消除,從而使得當(dāng)前協(xié)程重新進(jìn)入正常狀況。

          在一個處于恐慌狀況的協(xié)程退出之前,其中的恐慌不會蔓延到其它協(xié)程。 如果一個協(xié)程在恐慌狀況下退出,它將使整個程序崩潰。看下面的兩個例子:

          package mainimport (     "fmt"     "time")func p(a, b int) int {     return a / b}func main() {     go func() {         fmt.Println(p(1, 0))     }()     time.Sleep(time.Second)     fmt.Println("程序正常退出~~~")}

          output:

          panic: runtime error: integer pide by zero  goroutine 6 [running]: main.p(...)         /Users/didi/Desktop/golang/defer.go:9 main.main.func1()         /Users/didi/Desktop/golang/defer.go:14 +0x12 created by main.main         /Users/didi/Desktop/golang/defer.go:13 +0x39exit status 2

          p函數(shù)發(fā)生panic(除數(shù)為0),因為所在協(xié)程沒有恐慌恢復(fù)機(jī)制,導(dǎo)致整個程序崩潰。
          如果p函數(shù)所在協(xié)程加上恐慌恢復(fù)(defer + recover),程序便可正常退出。

          package mainimport (     "fmt"     "time")func p(a, b int) int {     return a / b}func main() {     go func() {         defer func() {             v := recover()             if v != nil {                 fmt.Println("恐慌被恢復(fù)了:", v)             }         }()         fmt.Println(p(1, 0))     }()     time.Sleep(time.Second)     fmt.Println("程序正常退出~~~")}

          output:

          恐慌被恢復(fù)了: runtime error: integer pide by zero 程序正常退出~~~

          贊(0)
          分享到: 更多 (0)
          網(wǎng)站地圖   滬ICP備18035694號-2    滬公網(wǎng)安備31011702889846號