Go语言的异常处理

本文介绍Go语言中的异常处理,Go中的异常处理与通常的编程语言(如:Java、PHP)不同,没有使用try...catch...捕获机制,而是具有自己的特点。

Go语言的异常处理

错误处理

先看一下go的底层提供的错误处理接口与方法

Go底层接口

package errors

type error interface {
    Error() string
}

实现类 errorString

package errors

func New(text string) error {
    return &errorString{ text }
}

type errorString struct {
    s string
}

func (e *errorString) Error() string {
    return e.s
}

实现方法

package fmt

import (
    "errors"
)

func Errorf(format string, args ...interface{}) error {
   return errors.New(Sprintf(format, args...))
}

接口的应用

package main

import (
   "errors"
   "fmt"
)

func main() {
   s := errors.New("123")
   fmt.Println(s)

   err := fmt.Errorf("我的名字:%s,年龄:%d", "董俊", 29)
   fmt.Println(err.Error())
}

实现类与实现方法的打印是没有实际意义的,我们看一个实际应用的例子

package main

import (
   "errors"
   "fmt"
)

func calc(a, b int) (n int , err error) {
   if (b == 0) {
      err = errors.New("除数不能为0")
   } else {
      n = a / b
   }
   return
}

func main() {
   a := 10
   b := 0
   n, err := calc(a, b)
   if err != nil {
      fmt.Println(err.Error())
   } else {
      fmt.Printf("%d / %d = %d", a, b, n)
   }
}

异常处理

panic

通常情况下,向程序调用方报告错误状态的方式可以是一个额外的 error 类型值。Go底层函数大量使用了这种方式,返回多返回值,第二个返回值通常是一个 error 类型值,用于判断调用的函数中是否有错误。

当某些不应该发生的场景发生时,我们就应该调用 panic。

我们不应通过 panic 函数来报告普通的错误,

而应该只把 panic 用来报告致命错误的一种方式。

一般而言,当 panic 异常发生时,程序会中断运行,并立即执行在该 goroutine 中被延迟的函数(defer机制)。随后,程序崩溃并输出日志信息。

日志信息包括 panic value 和函数调用的堆栈跟踪信息。

运行时异常错误

package main

import "fmt"

func calc() {
   defer func() {
      fmt.Println("defer后面调用的函数在 panic异常时也会被调用!")
   }()

   arr := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}

   total := 0
   for i := 0; i <= 10; i++ {
      // 当 i = 10时,数组索引越界了,就会抛出panic异常
      total += arr[i]
   }
   fmt.Println(total)
}

func main() {
   calc()
}

不是所有的 panic 异常都来自运行时,直接调用内置 panic 函数也会引发 panic 异常。

panic函数接受任何值作为参数。

func panic(v interface{})

直接调用内置panic函数

package main

import "fmt"

func calc() {

   defer func() {
      fmt.Println("defer后面调用的函数在 panic异常时也会被调用!")
   }()

   arr := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}

   total := 0
   for i := 0; i < 10; i++ {
      total += arr[i]
   }
   
   // 强制panic抛出异常
   panic("强制panic抛出异常,这里是异常信息!")
   
   fmt.Println(total)
}

func main() {
   calc()
}

recover

运行时 panic 异常一旦被引发就会导致程序崩溃。

这当然不是我们愿意看到的,因为谁也不能保证程序不会发生任何运行时错误。

不过,Go语言为我们提供了专门用于“拦截”运行时 panic 的内建函数 -- recover

它可以使当前的程序从运行时 panic 的状态中恢复并重新获得流程控制权。

func recover() interface{}

注意:recover只有在 defer调用的函数中有效

如果调用了内置函数 recover, 并且定义该 defer 语句的函数发生了 panic 异常,

recover 会使程序从 panic 中恢复,并返回 panic value。

导致 panic 异常的函数不会继续运行,但能正常返回。

在未发生 panic 时调用 recover,recover 会返回 nil。

package main

import "fmt"

func calc() {

   defer func() {
      //fmt.Println("defer后面调用的函数在 panic异常时也会被调用!")
      // fmt.Println(recover())
       if err := recover(); err != nil {
         fmt.Println(err)
       }
   }()

   arr := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}

   total := 0
   for i := 0; i <= 10; i++ {
      // 当 i = 10时,数组索引越界了,就会抛出panic异常
      total += arr[i]
   }

   fmt.Println(total)
}

func main() {
   calc()
}

相关文章

感觉本篇文章不错,对你有收获?

¥我要小额赞助,鼓励作者写出更好的教程
80 160 120

作者:

  • 出处: https://www.mi360.cn/articles/213
  • 本文版权归作者,欢迎转载,但未经作者同意必须保留 此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

评论区

最新评论

扫码关注