异常处理

Go的设计者认为其它语言异常处理太过消耗资源,且设计和处理复杂,导致使用者不能很好的处理错误,甚至觉得异常和错误处理起来麻烦而被忽视、忽略掉,从而导致程序崩溃。 为了解决这些问题,Go将错误处理设计的非常简单

  • 函数调用,返回值可以返回多值,一般最后一个值可以是error接口类型的值
  1. 如果函数调用产生错误,则这个值是一个error接口类型的错误
  2. 如果函数调用成功,则该值是nil
  • 检查函数返回值中的错误是否是nil,如果不是nil,进行必要的错误处理

 error是Go中声明的接口类型

type error interface {
    Error() string
}

 所有实现 Error() string 签名的方法,都可以实现错误接口。用Error()方法返回错误的具体描述。

package main

import (
    "fmt"
)

type Myerr struct {
    s string
}

// error接口中只有一个方法,因此实现了error接口
func (p *Myerr) Error() string {
    return p.s
}

// 构造实例,返回指针类型,也可以是*error
func NewMyerr(t string) *Myerr {
    return &Myerr{t}
}

func div(a, b int) (int, error) {
    if b == 0 {
        return 0, NewMyerr("除零异常")
    }
    return a / b, nil
}

func main() {
    err := NewMyerr("自定义error")
    fmt.Printf("%#v\n", err)
    fmt.Println(err.Error())
    var e1 error = err
    fmt.Printf("%#v\n", e1)
    fmt.Println(div(5, 0))
}
示例

下面是上面代码的返回:

 panic

panic发生时,往往会造成程序崩溃、服务终止等后果,所以没人希望它发生。但是, 如果在错误发生时,不及时panic而终止程序运行,继续运行程序恐怕造成更大的损失,付出更加惨痛的 代价。所以,有时候,panic导致的程序崩溃实际上可以及时止损,只能两害相权取其轻。 panic虽然不好,体验很差,但也是万不得已,可以马上暴露问题,及时发现和纠正问题。

panic产生

  • runtime运行时错误导致抛出panic,比如数组越界、除零
  • 主动手动调用panic(reason),这个reason可以是任意类型

panic执行

  • 逆序执行当前已经注册过的goroutine的defer链(recover从这里介入)
  • 打印错误信息和调用堆栈
  • 调用exit(2)结束整个进程

recover

recover即恢复,defer和recover结合起来,在defer中调用recover来实现对错误的捕获和恢复,让代码 在发生panic后通过处理能够继续运行。类似其它语言中try/catch。

err := recover() , v := err.(type) ,v就是 panic(reason) 中的reason,reason可以是任意类 型。

func div(a, b int) int {
    defer func() {
        err := recover()
        fmt.Printf("%T %[1]v\n", err)
        switch v := err.(type) {
        case string:
            fmt.Println("字符串", v)
        case runtime.Error:
            fmt.Printf("%T %[1]v\n", v)
        }
    }()
    r := a / b
    return r
}

func main() {
    fmt.Println(div(5, 0))
}

打印结果:

 一旦在某函数中panic,当前函数panic之后的语句将不再执行,开始执行defer。如果在defer 中错误被recover后,就相当于当前函数产生的错误得到了处理。当前函数执行完defer,当前函数退出 执行,程序还可以从当前函数之后继续执行。

有panic,一路向外抛出,但没有一处进行recover,也就是说没有地方处理错误,程序崩溃

有painc,有recover来捕获,相当于错误被处理掉了,当前函数defer执行完后,退出当前函数, 从当前函数之后继续执行。

posted on 2023-07-04 17:24  自然洒脱  阅读(25)  评论(0编辑  收藏  举报