错误与异常处理

在 go 中没有 try catch 的异常处理语句,但是有 defer,panic,recovor,error 来控制程序执行流程

panic

当某函数 fun 出发 panic 异常,fun 后面代码停止运行,转而去运行 defer 代码(如果有 defer),再然后结束 fun 函数,并将当前处理权交给 fun 的调用函数,recover 之后函数正常往下运行。panic 返回值通过 recover 函数获取,如果 panic 函数没有被调用或者没有返回值,那么 recover 返回 nil

recover 捕获panic异常

recover 函数本身是用来处理 panic,表示当前 goroutine 是否有 panic 产生,只有当 recover 函数写在 defer 中时候方能起到捕获 panic 异常的效果

recover 很像一个 try catch,一旦把异常捕获到了,之后的程序又是正常执行了

demo1:

package main

import "fmt"

/*
错误和异常的区别是什么?
·错误是可以预先知道结果的,如:做除法的时候被除数不能为0
·异常是不可预知的,大部分是因为程序员代码编写不规范导致,如下:
    ·空指针引用
    ·下标越界
    ·除数为0
    ·不应该出现的分支,如default
    ·并发读写相同map
    ·往关闭的通道写数据
    ·输入不应该引起的函数错误

panic用法:用来抛出错误,使用时可能导致主线程挂掉,同时其他协程都会挂掉。可以配合同级别的recover使用,保证主线程不挂掉
recover用法:将recover()写在defer中,在可能发生panic的地方之前,先调用此defer的东西,当程序遇到panic时,系统会
跳过后面的代码,执行defer中的代码,返回捕获到的panic的值


*/

func myPanic() {
    x := 10
    y := 0
    c := x / y
    //panic("我就是个错误")
    fmt.Println(c)

}

func main() {
    fmt.Println("hello world,cc")
    defer func() {  
        if err := recover(); err != nil {
            fmt.Println("出错了", err)
        }
    }()
    myPanic()
    fmt.Println("这里执行不了")
}

error 基本用法

err != nil 处理错误上方我们看到了 panic 处理异常的方式,这里我们再看看 error 处理错误的方式

func foo() error {
  // ...
}

func main() {
  // 异常处理
  if err := foo; err != nil {
    // ...
  }
}

新的处理方式

上面通过不断的判断 err!=nil 会很麻烦,原因我们可以试想一下,如果一个方法会返回 error,而我们需要多次调用它,这就意味着每调用一次,那么我们下面就要进行 err!=nil 来判定一次错误,这会非常麻烦,因为我们有什么方式可以优化它呢?

type foo struct {
    x Xxx
    e error
}

func (f *foo) bar() {
    if f.e != nil {
        return
    }
    f.e = foobar()
}

采用新的方式来判断错误,我们只需要把经常产生返回错误的方法 foobar() 封装起来让它不用总是返回 error,并且里头做一个判断,如果调用该固定返回 error 的方法之前错误不是 nil,则直接结束,如果错误是 nil,则结构体中 e 接续承接该固定返回 error 的方法,所以我们可以在调用好几轮这个 bar() 方法后,最后一步再去对 error 做判断

产生一个错误

// 返回值是 error 类型
errors.New("一个新错误")

自定义错误

因为 error 接口有一个 Error 方法,当我们实现这个方法时候,实际上也就是实现了这个接口,也就是说自己的这个 struct 也成为了 error 接口

type foo struct {
    // ...
}

func (f foo) Error() string {
    // ...
}

当实现了 error 接口之后打印就能看到错误信息了

error 实践用法

当我们需要判断 error 是不是哪种 error 的时候我们可以使用 errors.Is() 函数,这个是在 go1.13 之后出现的很好判定 err 的用法

err := io.EOF
err = fmt.Errorf("xxxxxxx%w", io.EOF)
// 下方 if 是 true
if errors.Is(err, io.EOF) {
    fmt.Println("Is函数可以用来明确此 error 是不是某种异常,虽然 err != io.EOF")
}

还有errors.As()用力啊判定 err 是不是某一种类型

用panic 还是 error?

一般而言只用 error 错误处理,panic 是重大异常;error 是程序员可以预知的错误,panic 是程序员预料之外的异常

所以有一个原则就是我们写代码时候尽量使用 error 进行错误处理,尽量去避免 panic 处理,触发实在遇到了

参考:golang异常处理panic recover error基本介绍_golang的recover如何获取行号_abcnull的博客-CSDN博客

你可能感兴趣的:(go,golang,开发语言,后端)