有关defer,参见Golang中的defer


recover


使用panic抛出异常后, 将立即停止当前函数的执行并运行所有被defer的函数,然后将panic抛向上一层,直至程序carsh。但是也可以使用被defer的recover函数来捕获异常阻止程序的崩溃,recover只有被defer后才是有意义的。

1
2
3
4
5
6
7
8
9
10
func main() {

print(123)

print(456)
panic("throw an error")

print(678) //IDE会有提示: Unreachable code

}

结果:

1
2
3
4
5
123456panic: throw an error

goroutine 1 [running]:
main.main()
/Users/shuangcui/explore/panicandrecover.go:31 +0x67

使用recover()捕获异常:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
func main() {

print(123)

defer func() {
if err := recover(); err != nil {
print("recover it")
}
}()

print(456)
panic("throw an error")

print(678) //IDE会有提示: Unreachable code

}

结果为:

1
123456recover it

如果有两个recover,则捕获异常的是后一个

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
func main() {

print(123)

defer func() {
if err := recover(); err != nil {
print("recover it")
}
}()

defer func() {
if err := recover(); err != nil {
print("复原!")
}
}()

print(456)
panic("throw an error")

print(678) //IDE会有提示: Unreachable code

}

结果为:

1
123456复原!

panic之后的任何代码都不会继续执行

前提是panic不在if里面

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
package main

import "fmt"

func main() {
defer_call()
fmt.Println("333 Helloworld")
}

func defer_call() {
defer func() {
fmt.Println("11111")
}()

defer func() {
fmt.Println("22222")
}()

defer func() {
if r := recover(); r != nil {
fmt.Println("Recover from r : ", r)
}
}()

defer func() {
fmt.Println("33333")
}()

fmt.Println("111 Helloworld")

panic("Panic 1!")


//使用panic抛出异常后, 将立即停止当前函数的执行并运行所有被defer的函数,然后将panic抛向上一层, 直至程序carsh

//但是也可以使用被defer的recover函数来捕获异常阻止程序的崩溃,recover只有被defer后才是有意义的。

panic("Panic 2!") //panic1之后的panic2没有任何机会会被执行, panic2之后的任何代码更没有任何机会被执行

fmt.Println("222 Helloworld")
}

输出为:

1
2
3
4
5
6
111 Helloworld
33333
Recover from r : Panic 1!
22222
11111
333 Helloworld

对于goroutine中的panic,recover是无法恢复的~

goroutine中的recover,同样无法恢复协程外的panic

主方法中的recover,也可以恢复子方法里的panic;

但如果go subfunc(),则同样无法捕获subfunc中的异常

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
func main() {

fmt.Println(123)

defer fmt.Println(999)

defer func() {
if err := recover(); err != nil {
fmt.Println("恢复异常:",err)
}

}()
subfunc()

}

func subfunc() {

defer fmt.Println(888)
panic("出现了bug")

defer fmt.Println(456)

}

结果为:

1
2
3
4
123
888
恢复异常: 出现了bug
999


拓展&参考:

golang panic和recover 实现原理