Go-defer,panic,recover

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

defer

文法:

defer function_name() 

簡單來講,在defer所在函數執行完所有的代碼之後,會自動執行defer的這個函數。

樣本一(準系統)

package mainimport "fmt"/*D:\examples>go run helloworld.gofirstsecondD:\examples>*/func main() {    defer second()    first()}func first() {    fmt.Println("first")}func second() {    fmt.Println("second")}

樣本二(函數局部性)

package mainimport "fmt"/*D:\examples>go run helloworld.gofirstthirdfirstsecondD:\examples>*/func main() {    defer second()    first()    third()}func first() {    fmt.Println("first")}func second() {    fmt.Println("second")}func third() {    defer first()    fmt.Println("third")}

樣本三(棧特性)

package mainimport "fmt"/*D:\examples>go run helloworld.gofirstthirdsecondD:\examples>*/func main() {    defer second()    defer third()    first()}func first() {    fmt.Println("first")}func second() {    fmt.Println("second")}func third() {    fmt.Println("third")}

使用情境

主要用於資源需要釋放的情境。比如開啟一個檔案,最後總是要關閉的。而在開啟和關閉之間,會有諸多的處理,可能會有諸多的if-else、根據不同的情況需要提前返回。在傳統語言中,return之前都需要一一調用close()。

而Go的defer就將事情變得簡單了,open()之後,直接就用defer“註冊”一個close()。虛擬碼:

f, = os.open(filename)defer f.close()do_something()if (condition_a) {return}do_something_again() if (condition_b) {return}do_further_things()

panic & recover

先給出https://golang.org/pkg/builtin/上的函數說明。

panic

func panic(v interface{})

The panic built-in function stops normal execution of the current goroutine. When a function F calls panic, normal execution of F stops immediately. Any functions whose execution was deferred by F are run in the usual way, and then F returns to its caller. To the caller G, the invocation of F then behaves like a call to panic, terminating G’s execution and running any deferred functions. This continues until all functions in the executing goroutine have stopped, in reverse order. At that point, the program is terminated and the error condition is reported, including the value of the argument to panic. This termination sequence is called panicking and can be controlled by the built-in function recover.

recover

func recover() interface{}

The recover built-in function allows a program to manage behavior of a panicking goroutine. Executing a call to recover inside a deferred function (but not any function called by it) stops the panicking sequence by restoring normal execution and retrieves the error value passed to the call of panic. If recover is called outside the deferred function it will not stop a panicking sequence. In this case, or when the goroutine is not panicking, or if the argument supplied to panic was nil, recover returns nil. Thus the return value from recover reports whether the goroutine is panicking.

要點

  • panic相當於一個運行時異常
  • 遇到panic的時候,會停止當前函數剩下來的語句,但在退出該函數之前,會執行defer的語句
  • 依據函數調用層次,panic依次終止每個函數,直至main()。

panic樣本

package mainimport "fmt"/*D:\examples>go run helloworld.gof.1g.1h.1h.defer()g.defer()panic: panic in h()goroutine 1 [running]:panic(0x495360, 0xc04203a230)        C:/Go/src/runtime/panic.go:500 +0x1afmain.h()        D:/examples/helloworld.go:54 +0x12bmain.g()        D:/examples/helloworld.go:45 +0xeemain.f()        D:/examples/helloworld.go:38 +0xabmain.main()        D:/examples/helloworld.go:29 +0x1bexit status 2D:\examples>*/func main() {    f() // Line Number: 29}func final_print(msg string) {    fmt.Println(msg)}func f() {    fmt.Println("f.1")    g() // Line Number: 38    fmt.Println("f.2")}func g() {    defer final_print("g.defer()")    fmt.Println("g.1")    h() // Line Number: 45    fmt.Println("g.2")}func h() {    defer final_print("h.defer()")    fmt.Println("h.1")    panic("panic in h()") // Line Number: 52    fmt.Println("h.2")}

panic & defer & recover

recover相當於try-catch的catch部分,使得panic不再傳遞。而defer相當於try-catch-final的final部分。

package mainimport "fmt"/*D:\examples>go run helloworld.gof.1g.1h.1h.defer()g.defer()panic in h()f.2D:\examples>*/func main() {    f()}func final_print(msg string) {    fmt.Println(msg)}func f() {    fmt.Println("f.1")    g()    fmt.Println("f.2")}func g() {    defer func() {          str := recover()          fmt.Println(str)    }()    defer final_print("g.defer()")    fmt.Println("g.1")    h()    fmt.Println("g.2")}func h() {    defer final_print("h.defer()")    fmt.Println("h.1")    panic("panic in h()")    fmt.Println("h.2")}

擷取數組元素

接下來再給一個例子,擷取數組元素,處理數組訪問越界的問題。

package mainimport "fmt"/*D:\examples>go run helloworld.goa[0]=1[true]a[1]=2[true]a[2]=3[true]a[3]=4[true]a[4]=5[true]runtime error: index out of range [set to default value -1]a[5]=-1[false]runtime error: index out of range [set to default value -1]a[6]=-1[false]runtime error: index out of range [set to default value -1]a[7]=-1[false]runtime error: index out of range [set to default value -1]a[8]=-1[false]runtime error: index out of range [set to default value -1]a[9]=-1[false]D:\examples>*/func main() {    a := [5]int {1,2,3,4,5}    for i := 0; i < 10; i++ {        item, ok := get(i, a)        fmt.Printf("a[%d]=%d[%v]\n", i, item, ok)    }}func get(i int, a [5]int) (ret int, ok bool) {    ok = true     defer func() {        err := recover()        if err != nil {            fmt.Println(err, "[set to default value -1]")            ret = -1            ok = false        }    }()     ret = a[i]    return}
相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.