go中的error小结

  • go中的error

    • error和panic
    • error接口
    • go中err的困局
    • 推荐方法
    • 总结
    • 参考

go中的error

go中的错误处理,是通过返回值的形式来出来,要么你忽略,要么你处理(处理也可以是继续返回给调用者),对于golang这种设计方式,我们会在代码中写大量的if判断,以便做出决定。

func main() {
	conent,err:=ioutil.ReadFile("filepath")
	if err !=nil{
		//错误处理
	}else {
		fmt.Println(string(conent))
	}
}

对于err如果是nil就代表没有错误,如果不是nil就代表程序出问题了,需要对错误进行处理了。

error和panic

error:可预见的错误

panic:不可预见的异常

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

panic 有两个合理的用例。

1、发生了一个不能恢复的错误,此时程序不能继续运行。 一个例子就是 web 服务器无法绑定所要求的端口。在这种情况下,就应该使用 panic,因为如果不能绑定端口,啥也做不了。

2、发生了一个编程上的错误。 假如我们有一个接收指针参数的方法,而其他人使用 nil 作为参数调用了它。在这种情况下,我们可以使用 panic,因为这是一个编程错误:用 nil 参数调用了一个只能接收合法指针的方法。

在一般情况下,我们不应通过调用panic函数来报告普通的错误,而应该只把它作为报告致命错误的一种方式。当某些不应该发生的场景发生时,我们就应该调用panic。

总结下panic的使用场景

1、空指针引用

2、下标越界

3、除数为0

4、不应该出现的分支,比如default

5、输入不应该引起函数错误

error接口

go中的error是一个接口类型

// The error built-in interface type is the conventional interface for
// representing an error condition, with the nil value representing no error.
type error interface {
	Error() string
}

errors.New()是我们会经常使用的,我们来探究下这个函数

// src/errors/errors.go

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

type errorString struct {
	s string
}

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

使用 New 函数创建出来的 error 类型实际上是 errors 包里未导出的 errorString 类型,它包含唯一的一个字段 s,并且实现了唯一的方法:Error() string。

举个使用的栗子

func Sqrt(f float64) (float64, error) {
    if f < 0 {
        return 0, errors.New("math: square root of negative number")
    }
    // implementation
}

我们可以使用errors.New来定制我们需要的错误信息

但是对于上面的报错,我们知道是不知道报错的上下文信息的,我们就知道程序出错了,不利于我们错误的排查。我们可以使用fmt.Errorf来输出上下文信息。

if f < 0 {
    return 0, fmt.Errorf("math: square root of negative number %g", f)
}

通过fmt.Errorf我们不仅能打印错误,同时还能看到具体什么数数值引起的错误。它会先将字符串格式化,然后再调用errors.New来创建错误。

当我们想知道错误类型,并且打印错误的时候,直接打印 error

fmt.Println(err)

或者:

fmt.Println(err.Error)

fmt 包会自动调用 err.Error() 函数来打印字符串。

注意:对于err我们都是将err放在函数返回值的最后一个,同时对于会出错的函数我们都会返回一个err,当然对于一些函数,我们可能不确定之后是否会有错误的产生,所以一般也是预留一个err的返回。

go中err的困局

在go中,err的是通过返回值的形式返回。编程人员,要不处理,要不忽略。所以我们的代码就会大量的出现对错误的if判断。

出于对代码的健壮性考虑,我们对于每一个错误,都是不能忽略的。因为出错的同时,很可能会返回一个 nil 类型的对象。如果不对错误进行判断,那下一行对 nil 对象的操作百分之百会引发一个 panic

所以就造成了err满天飞。

还有比如,我们想对返回的error附加更多的信息后再返回,比如以上的例子,我们怎么做呢?我们只能先通过Error方法,取出原来的错误信息,然后自己再拼接,再使用errors.New函数生成新错误返回。

推荐方法

github.com/pkg/errors这个包给出了解决的方案。

它的使用非常简单,如果我们要新生成一个错误,可以使用New函数,生成的错误,自带调用堆栈信息。

func New(message string) error

如果有一个现成的error,我们需要对他进行再次包装处理,这时候有三个函数可以选择。

//只附加新的信息
func WithMessage(err error, message string) error

//只附加调用堆栈信息
func WithStack(err error) error

//同时附加堆栈和信息
func Wrap(err error, message string) error

这个错误处理库为我们提供了Cause函数让我们可以获得最根本的错误原因。

func Cause(err error) error {
	type causer interface {
		Cause() error
	}

	for err != nil {
		cause, ok := err.(causer)
		if !ok {
			break
		}
		err = cause.Cause()
	}
	return err
}

使用for循环一直找到最根本(最底层)的那个error

以上的错误我们都包装好了,也收集好了,那么怎么把他们里面存储的堆栈、错误原因等这些信息打印出来呢?其实,这个错误处理库的错误类型,都实现了Formatter接口,我们可以通过fmt.Printf函数输出对应的错误信息。

%s,%v //功能一样,输出错误信息,不包含堆栈
%q //输出的错误信息带引号,不包含堆栈
%+v //输出错误信息和堆栈

以上如果有循环包装错误类型的话,会递归的把这些错误都会输出。

总结

对于err我们都是将err放在函数返回值的最后一个,同时对于会出错的函数我们都会返回一个err,当然对于一些函数,我们可能不确定之后是否会有错误的产生,所以一般也是预留一个err的返回。

Go 中的 error 过于简单,以至于无法记录太多的上下文信息,对于错误包裹也没有比较好的办法。当然,这些可以通过第三方库来解决。

Go 语言使用 errorpanic 处理错误和异常是一个非常好的做法,比较清晰。至于是使用 error 还是 panic,看具体的业务场景。

参考

【Go语言(golang)的错误(error)处理的推荐方案】https://www.flysnow.org/2019/01/01/golang-error-handle-suggestion.html

【Golang error 的突围】https://www.cnblogs.com/qcrao-2018/p/11538387.html

【The Go Blog Error handling and Go】https://blog.golang.org/error-handling-and-go

【Go 1.13 errors 基本用法】https://segmentfault.com/a/1190000020398774

【Go与Error的前世今生】https://zhuanlan.zhihu.com/p/55975116

【Go 系列教程 —— 32. panic 和 recover】https://studygolang.com/articles/12785

【Golang错误和异常处理的正确姿势】https://www.jianshu.com/p/f30da01eea97

原文地址:https://www.cnblogs.com/ricklz/p/12683374.html

时间: 2024-10-15 00:32:06

go中的error小结的相关文章

hiredis中异步的实现小结

前言 一般情况下我们使用的都是hiredis的同步通信机制,这种机制下每当你向服务器发送命令请求,程序都会阻塞直到收到服务器的回复并处理.而如果采用异步通信,程序就不需要阻塞等待服务器的回复,而是直接继续执行后边的代码,当服务器回复到来后由程序中预先注册的回调函数来处理回复. 同步通信下程序写起来逻辑更清晰,代码量也少,但是由于每次请求都要停下来等待回复,可能会影响程序的运行速度.异步通信下程序逻辑会变得很复杂,你必须考虑回调函数的编写,并且需要多开一个线程来实现异步事件的处理,但是异步通信下程

[转] SpringBoot RESTful 应用中的异常处理小结

[From] https://segmentfault.com/a/1190000006749441 SpringBoot RESTful 应用中的异常处理小结 永顺 2016年08月29日发布 赞  |   6收藏  |  15 8.8k 次浏览 @ControllerAdvice 和 @ExceptionHandler 的区别 ExceptionHandler, 方法注解, 作用于 Controller 级别. ExceptionHandler 注解为一个 Controler 定义一个异常处

前端开发中的Error以及异常捕获

本文首发于公众号:符合预期的CoyPan 写在前面 在前端项目中,由于JavaScript本身是一个弱类型语言,加上浏览器环境的复杂性,网络问题等等,很容易发生错误.做好网页错误监控,不断优化代码,提高代码健壮性是一项很重要的工作.本文将从Error开始,讲到如何捕获页面中的异常.文章较长,细节较多,请耐心观看. 前端开发中的Error JavaScript中的Error JavaScript中,Error是一个构造函数,通过它创建一个错误对象.当运行时错误产生时,Error的实例对象会被抛出.

数据挖掘中分类算法小结

数据挖掘中分类算法小结 数据仓库,数据库或者其它信息库中隐藏着许多可以为商业.科研等活动的决策提供所需要的知识.分类与预测是两种数据分析形式,它们可以用来抽取能够描述重要数据集合或预测未来数据趋势的模型.分类方法(Classification)用于预测数据对象的离散类别(Categorical Label);预测方法(Prediction )用于预测数据对象的连续取值. 分类技术在很多领域都有应用,例如可以通过客户分类构造一个分类模型来对银行贷款进行风险评估;当前的市场营销中很重要的一个特点是强

关于在xml文件中的 error: invalid symbol: &#39;switch&#39; 错误

在xml布局文件中使用Switch控件时,出现error: invalid symbol: 'switch'报错,代码如下: <Switch android:id="@+id/switch" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textOn="开启" android:textOff="关

Socket程序中的Error#10054错误

近期使用winSock做的一个网络项目中,使用TCP+Socket连接编写的一个多线程的网络程序,功能是client负责不断地向server端发送数据,服务端负责接收数据.client是一个DLL,服务端程序是一个随机启动的NT Service服务程序. 程序在夜间无人操作的执行过程中,client常常不定时地出现错误号为:10054的错误,而server端并没有对应的提示.执行环境是win2000+sp4,这个问题出现得比較莫名其妙. 查了MSDN上的10054错误号说明:WSAECONNRE

STM32工程中出现 error: A1163E: Unknown opcode R0, , expecting opcode or Macro错误分析及处理

最近测试以前的一个程序,一般都是打开以前写的程序修改参数直接测试 但是发现以前的编译后出现错误. 奇怪了,以前的出现都是调试好了的啊,一般都是没有错误的,迅速找问题 跳转到错误代码行 代码区域 1 Heap_Size EQU 0x00000000 2 3 AREA HEAP, NOINIT, READWRITE, ALIGN=3 4 __heap_base 5 Heap_Mem SPACE Heap_Size 6 __heap_limit 7 8 PRESERVE8 9 THUMB ;指定为TH

C++中的“error:LNK2005 已经在*.obj中定义”异常问题

C++中的“error:LNK2005 已经在*.obj中定义”异常问题 异常现象如下:

java中String类小结

构建一个字符串 1.用字符串直接量: String message = new String("Welcome to java"); 2.用字符串直接量: String message = "Welcome to java"; 3.用字符数组 Char[] charArray = {'m', 'y'}; String message = new String(charArray); 不可变字符与限定字符串 String对象是不可变的,内容不能改变 java虚拟机为了