golang error 设计

栏目: Go · 发布时间: 5年前

内容简介:对于一开始写 go 代码的开发者来说,可能最受不了的一件事情就是对在 go 中,这样想要自定义一个

对于一开始写 go 代码的开发者来说,可能最受不了的一件事情就是对 error 的处理,之前听一个同事说他写到至今 go 代码,其中有将近 40% 的代码都是 if err != nil {...} ,确实让人有点崩溃。写 go 写了一段时间之后觉得也没什么,起码觉得这样看起来也挺清晰的。

在 go 中, error 是一个 interface{} 类型,它只包含一个 Error() 方法,类型声明如下:

type error interface {
    Error() string
}

这样想要自定义一个 error 就很简单,比如 net package 中定义 DNSError 就是按照如下方法定义的:

type DNSError struct {
    Err         string // description of the error
    Name        string // name looked for
    Server      string // server used
    IsTimeout   bool   // if true, timed out; not all timeouts set this
    IsTemporary bool   // if true, error is temporary; not all errors set this
}
 
func (e *DNSError) Error() string {
    if e == nil {
        return "
<nil>
 "
    }
    s := "lookup " + e.Name
    if e.Server != "" {
        s += " on " + e.Server
    }
    s += ": " + e.Err
    return s
}

</nil>

而在编写 go 代码时,最普遍使用的 error 实现是 errors package 中的,其中的代码也非常简单,只有几行:

package errors

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

type errorString struct {
	s string
}

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

在实际开发过程中,我们处理错误的时候如果仅仅是将报错展示出去那就很简单,只需要通过调用 Error() 方法就可以拿到报错的描述,但是大部分情况下,我们往往需要知道这是属于哪种类型的报错,以便做不同的处理,这时候便有好几种解决方案。

直接进行匹配

预先使用 errors packageNew(text string) 方法定义好 error ,然后将获取到的 error 同已经定义好的 error 做比较,因为最终获取到的 error 和已经定义好的 error 其实都是遵循 error interfacestruct 类型,而 golang 中的 struct 是可以进行比较的。比如在 gorm 这个数据库 ORMpackage 中,就使用了 errors package 来定义了 ErrRecordNotFound

// ErrRecordNotFound returns a "record not found error". Occurs only when attempting to query the database with a struct; querying with a slice won't return this error
var ErrRecordNotFound = errors.New("record not found")

说到这里,gorm 中有一个我觉得很有意思的一个设计,因为在数据库执行过程中会执行多条语句,此时可能会有多条 error 信息,gorm 的处理是定义了 type Errors []error 这样一个类型,然后让它遵循 error interface ,通过这样达到一个一条 error 包含多条 error 的目的。

通过 interface 的类型转换

有时候我们需要自己定义 error 类型以满足开发需求,比如除了仅仅知道报错信息之外,我们还需要针对报错增加错误码,因为 error 是一个 interface ,所以实现起来很简单。在具体开发过程中,拿到一条 error 对它进行类型转换,转换成自定义的 error 就可以做我们想做的操作了。

我们还是用 gorm 来举例,上面我们说 gorm 中定义了一个 Errors 类型,它遵循了 error interface ,并实际上是一个 []error 类型,所以我们拿到一条 error 可以对它做类型转换,比如下面这个方法:

// IsRecordNotFoundError returns true if error contains a RecordNotFound error
func IsRecordNotFoundError(err error) bool {
	if errs, ok := err.(Errors); ok {
		for _, err := range errs {
			if err == ErrRecordNotFound {
				return true
			}
		}
	}
	return err == ErrRecordNotFound
}

Go 2.0 Draft

虽说 go 目前的 error 处理写起来简单粗暴,看代码看起来也挺简单,但是毕竟这也都是 9102 年了,这种对错误的处理总觉得很落后,好在 Google 在 go 2 草案中开始对此进行了改进,增加了 checkhandle 两个关键字来对 error 进行处理,在这里简单介绍一下。

比如说我们需要实现一个 copyFile 的操作,根据 go 2 的草案,增加 checkhandle 之后,就很简单了:

func CopyFile(src, dst string) error {
	handle err {
		return err
	}

	r := check os.Open(src)
	defer r.Close()

	w := check os.Create(dst)
	handle err {
		w.Close()
		os.Remove(dst)
	}

	check io.Copy(w, r)
	check w.Close()

	return nil
}

其中,在需要检查 error 的操作中增加 check ,然后配合 handle 代码块来进行对 error 的处理, handle 代码块可以有多个,会按照从下往上的顺序以此执行,这看上去感觉有点像 try-catch 的处理,比现在的错误处理写起来要爽很多。


以上所述就是小编给大家介绍的《golang error 设计》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

编译器设计

编译器设计

Keith Cooper、Linda Torczon / 郭旭 / 人民邮电出版社 / 2012-12 / 99.00元

深入剖析现代编译器运用的算法和技术 强调代码优化和代码生成 体现编译原理教学的最新理念 本书旨在介绍编译器构造法中的艺术和科学。书中深入分析现代编译器后端所用的算法和技术,重点讨论代码优化和代码生成,详细介绍了用几个编程语言编写的示例等。 Keith D. Cooper 莱斯大学计算机科学系计算工程专业Doerr特聘教授,曾任该系系主任。Cooper博士的研究课题涵盖过程间......一起来看看 《编译器设计》 这本书的介绍吧!

在线进制转换器
在线进制转换器

各进制数互转换器

随机密码生成器
随机密码生成器

多种字符组合密码

SHA 加密
SHA 加密

SHA 加密工具