首页 > Go 分布式学习利器(14)-- Go语言的错误处理

Go 分布式学习利器(14)-- Go语言的错误处理

1. Go 的错误机制

Go 语言的错误机制中与其他语言的主要差异如下:

  • 没有异常机制
  • error 类型实现了 error接口
    type error interface { Error() string
    }
    
  • 可以通过errors.New来快速创建错误实例
    errors.New(" num is not in range[0,100]")
    

如下测试代码演示基本的错误处理:

package error_testimport ("errors""testing"
)/* 斐波那契数列 */
func GetFibList(n int) ([]int,error){  // 两个返回值if n < 2 || n > 100 {  // 返回错误return nil, errors.New("n should in range [2..100]")}fibList := []int{ 1,1}for i := 2; i < n; i++ { fibList = append(fibList, fibList[i-1] + fibList[i-2])}return fibList,nil
}func TestFibArray(t *testing.T) { if v,err := GetFibList(-10);err != nil { t.Error(err)} else { t.Log(v)}
}

输出如下:

=== RUN   TestFibArrayerror_test.go:24: n should in range [2..100]
--- FAIL: TestFibArray (0.00s)

如果我们需要有多种错误类型的返回,那么就需要区分不同的错误,可以通过设置预置的错误类型来 快速简便得区分不同的错误

package error_testimport ("errors""testing"
)/*区分不同的错误类型*/
var LessThanTwo = errors.New("n should large than 2")
var BiggerThanHundred = errors.New("n should small than 100")/* 斐波那契数列 */
func GetFibList(n int) ([]int,error){  /* 两个返回值 */if n < 2 { return nil, LessThanTwo}if n > 100 { return nil, BiggerThanHundred}fibList := []int{ 1,1}for i := 2; i < n; i++ { fibList = append(fibList, fibList[i-1] + fibList[i-2])}return fibList,nil
}func TestFibArray(t *testing.T) { if v,err := GetFibList(-10);err != nil { t.Error(err)} else { t.Log(v)}
}

输出如下:

=== RUN   TestFibArrayerror_test.go:32: n should large than 2
--- FAIL: TestFibArray (0.00s)

2. 错误处理的最佳实践

按照我们以上代码的处理逻辑,我们能够发现函数有多个返回值的时候 如果每个返回值都需要判断,并作出对应的错误处理,这回让代码非常冗余。

所以一般针对有多个错误 返回值的多个函数,会直接判断错误返回值不为空,直到调用到最终正常的结果才返回。

如下函数针对多个函数的多个错误返回值的正常处理:

func GetFibList2( str string) { var (i interr errorlist []int)if i, err = strconv.Atoi(str); err != nil {  // 错误输出fmt.Println("Atoi error", err)return}if list,err = GetFibList(i); err != nil{  // 错误输出fmt.Println("GetFibList error",err)return}fmt.Println(list) // 直到所有函数都执行正常才最终输出
}

3. panic和recover

panic关键字是Go语言中程序异常退出的关键字

  • 用于不可以恢复的错误
  • panic 程序退出前 会执行 defer指定的函数,并打印函数调用栈

这里先对比一下panicos.Exit 两个异常退出函数的区别

  • os.Exit 退出时不会调用defer函数
  • os.Exit 退出时不会打印函数调用栈信息

如下测试代码:

package errorimport ("errors""fmt""testing"
)func TestPanicVsExit(t *testing.T){ defer func(){ fmt.Println("finally execute")}()fmt.Println("start")//	os.Exit(-1)panic(errors.New("something wrong"))
}

输出如下,可以看到panic能够打印调用栈和执行defer函数

=== RUN   TestPanicVsExit
start
finally execute
--- FAIL: TestPanicVsExit (0.00s)
panic: something wrong [recovered]panic: something wronggoroutine 18 [running]:
testing.tRunner.func1.1(0x11199c0, 0xc00008e4a0)/usr/local/Cellar/go/1.14.6/libexec/src/testing/testing.go:988 +0x30d
testing.tRunner.func1(0xc0000ce120)/usr/local/Cellar/go/1.14.6/libexec/src/testing/testing.go:991 +0x3f9
panic(0x11199c0, 0xc00008e4a0)/usr/local/Cellar/go/1.14.6/libexec/src/runtime/panic.go:969 +0x166
command-line-arguments.TestPanicVsExit(0xc0000ce120)/Users/zhanghuigui/go/src/test/ch10/error_test/panic_test.go:17 +0xd7
testing.tRunner(0xc0000ce120, 0x114b278)/usr/local/Cellar/go/1.14.6/libexec/src/testing/testing.go:1039 +0xdc
created by testing.(*T).Run/usr/local/Cellar/go/1.14.6/libexec/src/testing/testing.go:1090 +0x372
FAIL    command-line-arguments  0.663s

os.Exit(-1)则直接退出程序。

recover 关键字类似于我们C++/Java中 的try..catch关键字,能够防止程序异常后不会退出,而执行自己想要做的异常恢复或者对应的错误处理。

Go语言通过recover完成类似其他编译型语言的错误恢复处理。

如下简单测试代码:

package errorimport ("errors""fmt""testing"
)func TestPanicVsExit(t *testing.T){ defer func(){ if err := recover(); err != nil {  // 并没有做异常恢复,仅仅是把异常打出来fmt.Println("recover : ", err)}}()fmt.Println("start")panic(errors.New("something wrong")) // 通过panic 传入异常
}

最后的输出比较有趣,可以看到panic并没有让程序异常退出和打程序调用栈,异常错误直接被recover捕获,程序执行状态是PASS

=== RUN   TestPanicVsExit
start
recover from  something wrong
--- PASS: TestPanicVsExit (0.00s)

最常见的“错误恢复” 如下, 是不被建议使用的

	defer func(){ if err := recover(); err != nil {  // 并没有做异常恢复,仅仅是把异常打出来log.Error("recovered panic",err)}}()

这样的处理错误仅仅是把异常结果打印到日志中或者直接忽略掉,这个时候可能一些错误是系统异常造成的,容易形成僵尸进程。

即如果一些异常是系统性异常(内存分配异常,磁盘异常。。。等),可以直接让进程崩溃,并将该异常告知开发者,由他决定如何处理。

更多相关:

  • 能够在Linux系统下体验到原生界面的网易云音乐是件不错的事情,但是它总是经常性的出现网络异常,界面无响应的问题 为了听歌的体验,进行深入探究: 首先通过终端启用网易云音乐:sudo netease-cloud-music 会得到网易云音乐运行时的信息,比如一些出错的信息 其实我已经解决了首要的问题(QSslSocket错误),因...

  • 【错误页面处理】 訪问一个错误的控制器 訪问一个错误的方法 有些控制器和方法禁止訪问   以上訪问会提示错误信息 404  403 以上错误信息是不方便给外边用户看到的。 1. 安全隐患 2. 用户体验不好 错误信息在site/error这个地方定义的。   如今我们要自己定义错误页面来显示我们的错误信息 转载于:...

  • 噪声的来源: 1、noise in y 2、noise in x 在有noise的情况下,vc bound还会work么??? 之前,x ~ p(x)  现在 y ~ P( y | x ) 在hoeffding的部分,只要 (x, y) 联合分布满足某个分布, 结果是一致的。   error measure:打分衡量f和g的距离 1、...

  • 在IIS7.5打开网页的时候,提示: HTTP 错误 500.0 - Internal Server Error 调用 LoadLibraryEx 失败,在 ISAPI 筛选器 C:WindowsMicrosoft.NETFrameworkv4.0.30319\aspnet_filter.dll,经过排除发现原来是两个斜杠导...

  • 对ARM异常(Exceptions)的理解 1 .对 ARM 异常( Exceptions )的理解 所有的系统引导程序前面中会有一段类似的代码,如下: .globl _start                    ;系统复位位置 _start: b       reset            ;各...

  • org.apache.shiro.authc.pam.UnsupportedTokenException org.apache.shiro.authc.UnknownAccountExce...

  • 什么是异常处理 异常就是程序运行时发生错误的信号(在程序出现错误时,则会产生一个异常,若程序没有处理它,则会抛出该异常,程序的运行也随之终止),在python中,错误触发的异常如下 语法错误: 这种错误根本就过不了python解释器的语法检测,必须在程序执行前就改正逻辑错误:#TypeError:int类型不可迭代 for i in...

  • Ø  前言 本文主要记录 Android 的常见异常及解决办法,以备以后遇到相同问题时可以快速解决。   1.   java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.TextView.setText(java.la...

  • Python之路【第五篇】:面向对象及相关 Python之路【第五篇】:面向对象及相关 面向对象基础 基础内容介绍详见一下两篇博文: 面向对象初级篇面向对象进阶篇其他相关 一、isinstance(obj, cls)  检查是否obj是否是类 cls 的对象 1 2 3 4 5 6 class Foo(o...

  •     注意,前情提示: 本代码基于《Node.js(nodejs)对本地JSON文件进行增、删、改、查操作(轻车熟路)》 传送门Node.js(nodejs)对本地JSON文件进行增、删、改、查操作(轻车熟路)_你挚爱的强哥❤给你发来1条消息❤-CSDN博客   在/api/demo/文件夹下面创建CURD.base.j...

  •     注意,前情提示: 本代码基于《Node.js(nodejs)对本地JSON文件进行增、删、改、查操作(轻车熟路)》 传送门Node.js(nodejs)对本地JSON文件进行增、删、改、查操作(轻车熟路)_你挚爱的强哥❤给你发来1条消息❤-CSDN博客   在/api/demo/文件夹下面创建copyFileOrF...