zoukankan      html  css  js  c++  java
  • Go panic+defer+recover理解加使用

    业务逻辑中,Golang通过返回error捕获错误,但当遇到一些触发程序的异常时,会导致程序崩溃,这时就是需要recover这种捕获异常方式了,recover通常与defer同时出现

    Defer

    defer语句函数放入栈中,执行defer的顺序满足先进后出原则,严格按照这个顺序,不会因为return等操作就不执行

    举一个简单的recover和defer配合使用的例子

    import (
        "fmt"
        "time"
    )
    func main() {
        test()
        for {
            fmt.Println("main()下面的代码...")
            time.Sleep(time.Second)
        }
    }
    func test() {
        defer func() {
            err := recover() // recover()内置函数,可以捕获到异常
            if err != nil {  // 捕获到异常
                fmt.Println("err=", err)
            }
        }()
        num1 := 10
        num2 := 0
        res := num1 / num2
        fmt.Println("res=", res)
    }

    打印:

    err= runtime error: integer divide by zero
    main()下面的代码...
    main()下面的代码...

    使用defer函数的一些坑

    1.不要在循环中使用defer,defer函数会入栈,可能会因为爆栈而导致程序崩溃,解决办法(1.在循环之外定义defer,2.将循环体包成方法体,在方法体中调用defer)

    2.调用defer时参数问题,执行到defer函数时,就会进行参数复制(记住这个复制的时刻,并不是等最后执行的时候才是复制),此时复制是值复制(等同于普通函数的入参)

    3.defer语句延迟执行了一个匿名函数,因为这个匿名函数捕获了外部函数的局部变量v,这种函数我们一般叫闭包。闭包对捕获的外部变量并不是传值方式访问,而是以引用的方式访问

    func Inc() (v int) {
        defer func(){ v++ } ()
        return 42
    }
    print(Inc)#43

    another case

    func main() {
        for i := 0; i < 5; i++ {
            defer func() {
                fmt.Println(i)
            }()
        }
    }
    记录的是引用,最后加完的i就是5
    5 5 5 5 5

    4.跨协程失效,panic只会触发当前协程的defer函数

    func main() {
        defer println("in main")
        go func() {
            defer println("in goroutine")
            panic("")
        }()
    
        time.Sleep(1 * time.Second)
    }

    in goroutine

    panic : 

    1分钟后输出 in main

    5.失效的崩溃恢复,recover不在defer里面,所以不会被捕获到

    func main() {
        defer fmt.Println("in main")
        if err := recover(); err != nil {
            fmt.Println(err)
        }
    
        panic("unknown err")
    }

    6.嵌套崩溃

    func main() {
        defer fmt.Println("in main")
        defer func() {
            defer func() {
                panic("panic again and again")
            }()
            panic("panic again")
        }()
    
        panic("panic once")
    }
    in main
    panic: panic once
    	panic: panic again
    	panic: panic again and again
    goroutine 1 [running]:

    7.如果其他协程发生panic,不捕获的话会自己导致主线程和其他协程执行失败,并且在主线程无法捕获panic

  • 相关阅读:
    RabbitMQ笔记-死信队列与延时队列
    设计模式-迭代器模式
    RabbitMQ笔记-Demo(C#)
    RabbitMQ笔记-消息追踪【未完成】
    RabbitMQ笔记-安装&命令
    RabbitMQ笔记-Exchange、Queue、Message详细说明
    MySQL笔记-MVCC【没写】
    MySQL笔记-基础知识
    多线程笔记-基础知识
    在Redis中进行分页排序查询【转】
  • 原文地址:https://www.cnblogs.com/peterleee/p/13448587.html
Copyright © 2011-2022 走看看