panic
panic是个函数,有一个空接口类型的入参(可传任意类型,如字符串、error等等)
func main() {
fmt.Println(10)
panic("这是一个恐慌")
fmt.Println(20)
}
只会打印10,不会打印20,main函数非零退出
defer是个关键字,后面跟一个函数
func ReturnTest() string {
fmt.Println("我是return执行的")
return "return"
}
func DeferTest() string {
defer fmt.Println("我是defer执行的")
return ReturnTest()
}
func main(){
defer DeferTest()
fmt.Println("我是main")
}
执行结果为:
我是main
我是return执行的
我是defer执行的
由此可以看出,defer是最后执行的,比return还要靠后
recover
recover也是个函数,没有入参,出参是个空接口类型,具体返回什么类型取决于使用的场景:
如果recover()在defer后面的函数中调用,则如果goroutine panic了,则recover()函数返回panic函数的入参,同时panic会被压制住,相当于异常被catch住,程序不会非零退出了,否则返回nil。
如果recover()不是在defer后面的函数中调用,则返回nil,且不会压制panic。
package main
import (
"errors"
"fmt"
"reflect"
// "time"
)
func MayPanic(i int) int {
if i == 0 {
panic("不能为0")
} else if i < 0 {
panic(errors.New("不能小于0"))
}
return 1
}
func main() {
defer func() {
if r := recover(); r != nil {
fmt.Println("========================")
fmt.Println(r)
fmt.Println(reflect.TypeOf(r))
}
}()
fmt.Println("我应该先执行才对呀。。。。")
// i := MayPanic(0)
// i := MayPanic(-1)
i := MayPanic(10)
fmt.Println(i)
}
如果不理解可以把代码拷贝下来,然后把MayPanic依次打开看看输出结果就知道了
经典使用
package main
import (
"fmt"
"time"
)
func proc(){
panic("ok")
}
func main() {
go func() {
// 1 在这里需要你写算法
// 2 要求每秒调用一次proc函数
// 3 要求程序不能退出
}()
select{
}
}
package main
import (
"fmt"
"time"
)
func proc(){
panic("ok")
}
func main() {
go func() {
// 1 在这里需要你写算法
// 2 要求每秒调用一次proc函数
// 3 要求程序不能退出
t := time.NewTicker(time.Second)
for{
select {
case <-t.C:
go func(){
defer func(){
if err := recover(); err != nil {
fmt.Println(err)
}
}()
proc()
}()
}
}
}()
select{
}
}
try catch finally封装
package main
import (
"log"
)
type ExceptionStruct struct {
Try func()
Catch func(Exception)
Finally func()
}
type Exception interface{}
func Throw(up Exception) {
panic(up)
}
func (ex ExceptionStruct) Do() {
if ex.Finally != nil {
defer ex.Finally()
}
if ex.Catch != nil {
defer func() {
if e := recover(); e != nil {
ex.Catch(e)
}
}()
}
ex.Try()
}
func main() {
log.Println("开始执行...")
ExceptionStruct{
Try: func() {
log.Println("try...")
Throw("发生了错误")
},
Catch: func(e Exception) {
log.Println("exception=", e)
},
Finally: func() {
log.Println("Finally...")
},
}.Do()
log.Println("结束运行")
}