Golang错误处理机制

ShawnLee_123 · · 136 次点击 · · 开始浏览    

错误处理

1. error接口

Go语言引入了一个关于错误处理的标准模式。即error接口,该接口定义如下:

type error interface {
    Error() string
}

对于大多数函数,如果要返回错误,都可以按照如下方式返回,将error作为多重返回值的最后一个,
但这并不是强制的要求。

func Foo(param int) (n int, err error) {
    
}

n, err := Foo(0)
if err != nil {
    //错误处理
} else {
    //使用返回值n
}

1.1 error接口使用

应为Go语言灵活的特性,我们不用指定一个类型从error接口继承,我们只需要实现error接口所有的
函数即可。
下面代码是Go库中的实际函数

type PathError struct {
    Op   string
    Path string
    Err  string
}

func (e *PathError) Error() string {
    return e.Op + " " + e.Path + ": " + e.Err.Error()
}

实现这个错误类之后,我们就可以直接返回PathError变量了。当syscall.stat()失败返回err时,将
该err包包装到一个PathError对象中返回

func Stat(name string) (fi FileInfo, err error) {
    var stat syscall.Stat_t
    err = syscall.Stat(name, &stat)
    
    if err != nil {
        return nil, &PathError("stat", name, err)
    }
    return fileInfoFromStat(&stat, name), nil
}

如果我们处理错误时,希望获取详细的信息。那就要用到Go语言中的类型转换了。
Go语言的类型转换与其他语言有所不同。使用方法如下:

fi, err := os.Stat("a.txt")

if err != nil {
    if e, ok := err.(*os.PathError); ok && e.Err != nil {
        //获取PathError中的变量,并处理
    }
}

上面的例子中e, ok := err.(*os.PathError)就是将err的类型转换为PathError类型。

2. defer

关键字defer是Go语言中的一个特性。
在C语言中,文件句柄打开后,在不使用时要记得关闭,
所以我们要考虑非常多的情况,比如异常时的关闭和清理工作。defer关键字就很好的解决了这个
问题。比如下面的例子:

func CopyFile(dist, src string) (w int64, err error) {
    srcFile, err := os.Open(scr)
    if err != nil {
        return
    }
    defer srcFile.Close()
    
    dstFile, err := os.Create(dst)
    if err != nil {
        return
    }
    defer dstFile.Close()
    
    return io.Copy(dstFile, srcFile)
}

即使CopyFile函数中抛出异常,Go仍然会保证defer修饰的函数能正常执行。如果你觉得
一句话完不成清理工作,也可以在defer后面加一个匿名函数。

defer func() {
    //复杂的清理工作
}

defer遵循先进后出原则,一个函数中,最后一个defer会先执行。当然,如果你为defer的执行
顺序烦恼时,你有必要重新审视一下你的架构了。

3. panic和recover

Go语言引入了panic()和recover()函数来报告和处理运行时的错误和程序中的错误。

3.1 错误处理流程

在一个函数执行过程中调用panic()函数时,正常的函数执行流程将立刻终止,但是函数中
之前用defer关键字延迟执行的语句会正常执行。之后该函数将返回调用函数,并导致逐层
向上执行panic流程,直至所属的goroutine中所有正在执行的函数被终止。错误信息将被报告,
包括调用panic()函数时传入的参数。

3.2 recover

recover用于终止错误处理流程。一般情况下,recover()应该在一个使用defer关键字的函数中执行。以保证有效的截取错误处理流程。如果在没有发生异常的goroutine中明确调用恢复过程,会导致该goroutine所属进程打印异常信息后退出。

使用场景:

defer func() {
    if r := recover(); r != nil {
        log.Printf("Runtime error caught: %v", r)
    }
} ()

foo()

无论foo()函数中是否触发了错误处理流程。该匿名defer函数都会在函数退出时执行。如果
foo中触发了错误处理流程。recover将得以终止流程,如果传给panic函数的参数不为nil,
还会打印错误信息。


有疑问加站长微信联系(非本文作者)

本文来自:简书

感谢作者:ShawnLee_123

查看原文:Golang错误处理机制

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:1006366459

136 次点击  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传