• go中的panic defer recover


    panic

    panic是个函数,有一个空接口类型的入参(可传任意类型,如字符串、error等等)

    func main() {
        fmt.Println(10)
        panic("这是一个恐慌")
        fmt.Println(20)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    只会打印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")
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    执行结果为:
    我是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)
    }
    
    • 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

    如果不理解可以把代码拷贝下来,然后把MayPanic依次打开看看输出结果就知道了

    经典使用

    package main
    
    import (
    	"fmt"
    	"time"
    )
    
    func proc(){
    	panic("ok")
    }
    func main() {
    	
    	go func() {
    		// 1 在这里需要你写算法
    		// 2 要求每秒调用一次proc函数
    		// 3 要求程序不能退出
    	}()
    	select{
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    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{
    	}
    }
    
    • 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

    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("结束运行")
    }
    
    • 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
    • 42
    • 43
    • 44
    • 45
    • 46
  • 相关阅读:
    U8二开成果汇总
    有关环境变量
    14. UART串口通信
    01-目录结构
    Java泛型详解
    H3C交换机 万兆光模块可以插在千兆光口上使用吗?
    高频电子线路——分频网络
    间隔分区表导出指定的分区数据
    3.1、前端异步编程(超详细手写实现Promise;实现all、race、allSettled、any;async/await的使用)
    TikTok达人解锁的条件
  • 原文地址:https://blog.csdn.net/qq_42874635/article/details/126623619