go语言中的错误处理机制

基础

错误处理应该是工程的一部分,Golang中的error是一个interface类型,如下:

type error interface {
	Error() string
}

凡是实现Error()方法的结构,都可以作为错误处理。因此如果函数可能出现错误,那么可以在返回值的最后,返回一个错误,比如:

func foo() error {
	// ... do something
	return errors.New("foo error")
}

直接返回错误

直接返回错误,类似于直接返回字符串类型的错误,或者错误码之类的。字符串类型的错误,在基础部分提到了。错误码相当于Linux、C编程中的错误码,一般我们需要自己定义。举个例子:

package mypkg

type ErrCode int

const (
	ERR1 = 1
	ERR2 = 2
	ERR3 = 3
)

func sub(a, b int) (int, ErrCode) {
	if b < 0 {
		return 0, ERR1
	} else if a < b {
		return 0, Err2
	} else if a < 0 {
		return 0, Err3
	}
	return a - b
}

这种类型的错误,编写简单,但是有两个缺陷:

1、外层如果想要使用错误码,则需要引入这个包,容易出现循环引用的情况。

2、如果包内部修改返回的错误码类型,则外部使用到错误码的地方,都要进行相应的修改,破坏了封闭性。

对于第一个缺陷,可以使用一个第三方的包,专门存放错误码,这个方式值得商榷。永远不要通过判断Error()方法返回的字符串的值,来进行对应的错误处理!!!

返回自定义类型的错误

该方式可以返回自定义的类型,并通过断言自定义类型,来进行有关的错误处理;自定义类型可以携带更多的信息,代码实例:

package main

import (
	"errors"
	"fmt"
	"runtime/debug"
)

type MyError struct {
	Inner      error                  // 内粗错误
	Message    string                 // 自定义错误信息
	StackTrace string                 // 堆栈信息
	Misc       map[string]interface{} //其它的一些数据
}

func (myError MyError) Error() string {
	return myError.Message
}

func wrapError(err error, msg string, msgArgs ...interface{}) MyError {
	return MyError{
		Inner:      err,
		Message:    fmt.Sprintf(msg, msgArgs),
		StackTrace: string(debug.Stack()),
		Misc:       make(map[string]interface{}),
	}
}

func Handle(key int) error {
	if key < 0 {
		return wrapError(errors.New("key < 0"), "This is an error test")
	}
	return nil
}

func main() {
	if err := Handle(-1); err != nil {
		if e, ok := err.(MyError); ok {
			fmt.Printf("Inner: %v, Message: %v, StackTrace: %v\n",
				e.Inner, e.Message, e.StackTrace)  // 这里输出对应的数据
		}
	}
}

这种方式处理问题更加方便,但是仍然可能会有包循环引用的问题。

隐藏内部细节的错误处理

上述两种方式,可以适应一些场景,不过都无法解决可能存在循环依赖的问题。为此,我们使用github.com/pkg/errors的包来解决问题,给出一个代码实例。

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

其实上面的包装,很类似于Java的异常包装,被包装的error,其实就是Cause,在前面的章节提到错误的根本原因,就是这个Cause。所以这个错误处理库为我们提供了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。

以上就是关于golang中的错误处理机制的详细介绍的详细内容,更多请关注北单博客其它相关文章!

原创文章,作者:CFVCE,如若转载,请注明出处:https://www.beidanyezhu.com/a/26440.html

(0)
CFVCE的头像CFVCE
上一篇 2025-01-03 14:41:14
下一篇 2025-01-03

相关推荐

  • go语言和Java语言有哪些区别

    区别:1、Go不允许函数重载,必须具有方法和函数的唯一名称;java允许函数重载。2、Java默认允许多态,Go没有。3、Go代码可以自动扩展到多个核心;而Java并不总是具有足够…

  • go语言如何实现string转float

    go语言实现string转float的方法:首先创建一个go示例文件;然后定义一个字符串;最后通过“v1, err:=strconv.ParseFloat(v, 32)”方式将st…

  • Go语言有哪些优势

    Go语言有优势:1、学习曲线容易;2、开发效率和运行效率高;3、Go语言可以说是开发效率和运行效率二者的完美融合,天生的并发编程支持;4、Go语言拥有强大的编译检查、严格的编码规范…

    2025-01-05
  • go语言导包时“.”和“_”有什么区别

    区别:“_”操作其实只是引入该包;使用“_”操作引用包是无法通过包名来调用包中的导出函数,而是只是为了简单的调用其init()函数。“.”操作的含义就是这个包导入之后在你调用这个包…

    2025-01-05
  • go语言中run与build命令有哪些区别

    区别:“go run”命令可以编译并直接运行程序,但不会产生exe文件,运行速度也相应较慢;“go build”命令用于测试编译包,主要检查是否会有编译错误,会产生exe文件,运行…

    2025-01-05
  • go语言中普通函数与方法有什么区别

    区别:对于普通函数,接收者为值类型时,不能将指针类型的数据直接传递,反之亦然;对于方法,接收者为值类型时,可以直接用指针类型的变量调用方法,反过来同样也可以。 Go语言中普通函数与…

  • python语言和go语言哪个比较好

    Python和Go都是用于编写Web应用程序的强大的高级编程语言,它们之间有什么区别吗?下面本篇文章就来带大家认识一下Python和Go语言。 Go语言是什么? Go是一种通用编程…

  • Go语言结构体是什么

    这篇文章给大家分享的是有关Go语言结构体是什么的内容。小编觉得挺实用的,因此分享给大家做个参考。一起跟随小编过来看看吧。 Go 语言结构体 Go 语言中数组可以存储同一类型的数据,…

  • go语言如何从结构体中获取某个字段的值

    这篇文章主要介绍go语言如何从结构体中获取某个字段的值,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完! Go 语言提供了 user.Name 语法,来从 us…

  • go语言有哪些优点

    go语言的优点:1、可直接编译成机器码,不依赖其他库;2、静态类型语言,但是有动态语言的感觉,写起来的效率很高;3、语言层面支持并发;4、内置runtime,支持垃圾回收;5、简单…

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

分享本页
返回顶部