Golang panic recover

Golang的panic和recover非常影响效率,建议少用。panic类似c++的throw,可以抛出一个异常,recover经常用在defer中去捕获一个panic,使这个panic不再往上传递,这样程序可以继续往下运行。

为了更深入了解,例子如下:

1 package main
  2 
  3 import (
  4         "fmt"
  5 )
  6 
  7 func main() {
  8         fmt.Println("Hello, i am main begin..")
  9         defer func() { 
 10                 fmt.Printf("I am main-defer-1\n")  
 11               }()
 12         defer func() { 
 13                 fmt.Printf("I am main-defer-2\n")  
 14                }()
 15 
 16         foo()
 17 
 18         fmt.Println("Hello, i am main end..")
 19         
 20         defer func() { fmt.Printf("I am main-defer-3\n");  } ()

 21 }       

func foo() {
 24         fmt.Println("Hello, i am foo begin..")
 25         defer func() { 
 26                         fmt.Println("I am foo-defer-1")
 27                         
 28                         if r := recover(); r != nil {//这里捕获了panic,foo的调用者会以为foo是正常退出,foo后面的语句会运行
 29                                 fmt.Println("recover in foo,", r)
 30                         }
 31                         
 32                 }()
 33         defer func() { fmt.Println("I am foo-defer-2"); } ()
 34         i := 0
 35         fmt.Printf("3/0 = %d\n", 3/i)<<<<模拟panic

 36   }

运行结果:

root@ubuntu:recoverPanic# go run Recover.go 
Hello, i am main begin..
Hello, i am foo begin..
I am foo-defer-2
I am foo-defer-1
recover in foo, runtime error: integer divide by zero
Hello, i am main end..
I am main-defer-3
I am main-defer-2
I am main-defer-1

root@ubuntu:recoverPanic# 

我们看看不用recover捕获panic的结果:

1 package main
  2 
  3 import (
  4         "fmt"
  5 )
  6 
  7 func main() {
  8         fmt.Println("Hello, i am main begin..")
  9         defer func() { 
 10                 fmt.Printf("I am main-defer-1\n")  
 11               }()
 12         defer func() { 
 13                 fmt.Printf("I am main-defer-2\n")  
 14                }()
 15 
 16         foo()
 17 
 18         fmt.Println("Hello, i am main end..")
 19 
 20         defer func() { fmt.Printf("I am main-defer-3\n");  } ()
 21 }    

 22       

23 func foo() {

 24         fmt.Println("Hello, i am foo begin..")
 25         defer func() { 
 26                         fmt.Println("I am foo-defer-1")
 27                         /*<<<<<<<<注释掉recover,panic会一直往上传递,foo后面的语句没有运行。
 28                         if r := recover(); r != nil {
 29                                 fmt.Println("recover in foo,", r)
 30                         }
 31                         */
 32                 }()
 33         defer func() { fmt.Println("I am foo-defer-2"); } ()
 34         //i := 0
 35         //fmt.Printf("3/0 = %d\n", 3/i)
 36         panic(3) <<<这里改为panic调用。
 37 
 38 }

root@ubuntu:recoverPanic# go run Recover.go 
Hello, i am main begin..
Hello, i am foo begin..
I am foo-defer-2

I am foo-defer-1

<<<<foo 后面的语句没有运行,但是foo前面注册的defer会先运行,才退出main。

I am main-defer-2
I am main-defer-1
panic: 3


goroutine 1 [running]:<<<下面的输出有点像gdb的back trace
main.foo()
/root/my_go/recoverPanic/Recover.go:36 +0x109
main.main()
/root/my_go/recoverPanic/Recover.go:16 +0xdb
exit status 2

root@ubuntu:recoverPanic# 

==================================runtime也可以输出堆栈信息:

1 package main
  2 
  3 import (
  4         "fmt"
  5         "runtime"
  6         "os"
  7 )     
  8      
  9 func main() {
 10         fmt.Println("Hello, i am main begin..")
 11         defer func() { <<<<<这里用runtime的Stack输出堆栈信息,可以用在recover捕获panic中用来打印堆栈。
 12                 fmt.Printf("I am main-defer-1\n")  
 13                 var buf [4096]byte
 14                 n := runtime.Stack(buf[:], false)
 15                 os.Stdout.Write(buf[:n])
 16               }()
 17         defer func() { 
 18                 fmt.Printf("I am main-defer-2\n")  
 19                }()
 20 
 21         foo()
 22 
 23         fmt.Println("Hello, i am main end..")
 24 
 25         defer func() { fmt.Printf("I am main-defer-3\n");  } ()

 26 }
 27 
 28 func foo() {
 29         fmt.Println("Hello, i am foo begin..")
 30         defer func() { 
 31                         fmt.Println("I am foo-defer-1")
 32                         /*
 33                         if r := recover(); r != nil {
 34                                 fmt.Println("recover in foo,", r)
 35                         }
 36                         */
 37                 }()
 38         defer func() { fmt.Println("I am foo-defer-2"); } ()
 39         //i := 0
 40         //fmt.Printf("3/0 = %d\n", 3/i)
 41         panic(3)
 42 
 43 }

root@ubuntu:recoverPanic# go run Recover.go 
Hello, i am main begin..
Hello, i am foo begin..
I am foo-defer-2
I am foo-defer-1
I am main-defer-2
I am main-defer-1
goroutine 1 [running]:<<<runtime 输出的比程序崩溃自己输出的多两行:
main.main.func1()
/root/my_go/recoverPanic/Recover.go:14 +0x8f
panic(0x48c840, 0xc42000e218)
/usr/lib/go-1.8/src/runtime/panic.go:489 +0x2cf
main.foo()
/root/my_go/recoverPanic/Recover.go:41 +0x109
main.main()
/root/my_go/recoverPanic/Recover.go:21 +0xdb
panic: 3


goroutine 1 [running]:<<<<<程序崩溃自己的输出的还是会输出,不会英文调用runtime而不输出。
main.foo()
/root/my_go/recoverPanic/Recover.go:41 +0x109
main.main()
/root/my_go/recoverPanic/Recover.go:21 +0xdb
exit status 2
root@ubuntu:recoverPanic# 


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值