zoukankan      html  css  js  c++  java
  • 14-异常处理

    异常处理

    defer panic recover

    defer 表示延迟调用,即便程序出现严重错误,也会执行
    panic  就是python中的raise(主动抛出异常)
    recover 恢复程序,继续执行

    什么是panic

    在 Go 语言中,程序中一般是使用[错误]来处理异常情况。对于程序中出现的大部分异常情况,错误就已经够用了。
    
    但在有些情况,当程序发生异常时,无法继续运行。在这种情况下,我们会使用 panic 来终止程序。当[函数]发生 panic 时,它会终止运行,在执行完所有的[延迟]函数后,
    程序控制返回到该函数的调用方。这样的过程会一直持续下去,直到当前[协程]的所有函数都返回退出,然后程序会打印出 panic 信息,接着打印出堆栈跟踪(Stack Trace),
    最后程序终止。在编写一个示例程序后,我们就能很好地理解这个概念了。

    什么时候使用panic

    需要注意的是,你应该尽可能地使用错误,而不是使用 panic 和 recover。只有当程序不能继续运行的时候,才应该使用 panic 和 recover 机制。

    panic 有两个合理的用例。

    1. 发生了一个不能恢复的错误,此时程序不能继续运行。 一个例子就是 web 服务器无法绑定所要求的端口。在这种情况下,就应该使用 panic,因为如果不能绑定端口,啥也做不了。
    2. 发生了一个编程上的错误。 假如我们有一个接收指针参数的方法,而其他人使用 nil 作为参数调用了它。在这种情况下,我们可以使用 panic,因为这是一个编程错误:用 nil 参数调用了一个只能接收合法指针的方法。

    panic示例

    package main
    
    import (  
        "fmt"
    )
    
    func fullName(firstName *string, lastName *string) {  
        if firstName == nil {
            panic("runtime error: first name cannot be nil")
        }
        if lastName == nil {
            panic("runtime error: last name cannot be nil")
        }
        fmt.Printf("%s %s
    ", *firstName, *lastName)
        fmt.Println("returned normally from fullName")
    }
    
    func main() {  
        firstName := "Elon"
        fullName(&firstName, nil)
        fmt.Println("returned normally from main")
    }

    发生panic时的defer

    我们重新总结一下 panic 做了什么。当函数发生 panic 时,它会终止运行,在执行完所有的延迟函数后,程序控制返回到该函数的调用方。这样的过程会一直持续下去,直到当前协程的所有函数都返回退出,然后程序会打印出 panic 信息,接着打印出堆栈跟踪,最后程序终止

    在上面的例子中,我们没有延迟调用任何函数。如果有延迟函数,会先调用它,然后程序控制返回到函数调用方

    recover

    recover 是一个内建函数,用于重新获得 panic 协程的控制。

    只有在延迟函数的内部,调用 recover 才有用。在延迟函数内调用 recover,可以取到 panic 的错误信息,并且停止 panic 续发事件(Panicking Sequence),程序运行恢复正常。如果在延迟函数的外部调用 recover,就不能停止 panic 续发事件。

    package main
    
    import (  
        "fmt"
    )
    
    func recoverName() {  
        if r := recover(); r!= nil {
            fmt.Println("recovered from ", r)
        }
    }
    
    func fullName(firstName *string, lastName *string) {  
        defer recoverName()
        if firstName == nil {
            panic("runtime error: first name cannot be nil")
        }
        if lastName == nil {
            panic("runtime error: last name cannot be nil")
        }
        fmt.Printf("%s %s
    ", *firstName, *lastName)
        fmt.Println("returned normally from fullName")
    }
    
    func main() {  
        defer fmt.Println("deferred call in main")
        firstName := "Elon"
        fullName(&firstName, nil)
        fmt.Println("returned normally from main")
    }
  • 相关阅读:
    单例设计模式
    C#做窗体皮肤
    常用的数组的操作
    C#调试方法
    Timer
    程序对对象的字段的代码简写
    nginx upstream的几种配置方式
    ava如何实现系统监控、系统信息收集、sigar开源API的学习(转)
    vsftpd 被动模式与主动模式
    MySQL安装详解(V5.5 For Windows)
  • 原文地址:https://www.cnblogs.com/wangcuican/p/12035732.html
Copyright © 2011-2022 走看看