Go-defer,panic,recover
defer
語法:
defer function_name()簡單來講,在defer所在函數執行完所有的代碼之后,會自動執行defer的這個函數。
示例一(基本功能)
package main import "fmt"/* D:\examples>go run helloworld.go first secondD:\examples> */ func main() {defer second()first() }func first() {fmt.Println("first") }func second() {fmt.Println("second") }示例二(函數局部性)
package main import "fmt"/* D:\examples>go run helloworld.go first third first secondD:\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 main import "fmt"/* D:\examples>go run helloworld.go first third secondD:\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 main import "fmt"/* D:\examples>go run helloworld.go f.1 g.1 h.1 h.defer() g.defer() panic: panic in h()goroutine 1 [running]: panic(0x495360, 0xc04203a230)C:/Go/src/runtime/panic.go:500 +0x1af main.h()D:/examples/helloworld.go:54 +0x12b main.g()D:/examples/helloworld.go:45 +0xee main.f()D:/examples/helloworld.go:38 +0xab main.main()D:/examples/helloworld.go:29 +0x1b exit 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: 38fmt.Println("f.2") }func g() {defer final_print("g.defer()")fmt.Println("g.1")h() // Line Number: 45fmt.Println("g.2") }func h() {defer final_print("h.defer()")fmt.Println("h.1")panic("panic in h()") // Line Number: 52fmt.Println("h.2") }panic & defer & recover
recover相當于try-catch的catch部分,使得panic不再傳遞。而defer相當于try-catch-final的final部分。
package main import "fmt"/* D:\examples>go run helloworld.go f.1 g.1 h.1 h.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 main import "fmt"/* D:\examples>go run helloworld.go a[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 = -1ok = false}}() ret = a[i]return }總結
以上是生活随笔為你收集整理的Go-defer,panic,recover的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 二次元导航HTML源码 可做个人主页
- 下一篇: WEB服务器和中间件