最近校招又开始了,我也接到了一些面试工作,当我问「你觉得自己有什么优势」时,十个人里有八个的回答里会有一条「精力充沛,能加班」。 怪不得国家都给认证了:新生代农民工。合着我们这根本就不是什么脑力劳动者,而是靠出卖体力的苦劳力。 好了,废话不多说,肝文还确实需要体力。 这篇来说说 Go 的错误处理。 错误处理错误处理相当重要,合理地抛出并记录错误能在排查问题时起到事半功倍的作用。 Go 中有关于错误处理的标准模式,即 error 接口,定义如下: type error interface { Error() string} 大部分函数,如果需要返回错误的话,基本都会将 error 作为多个返回值的最后一个,举个例子:
我们也可以使用自定义的 error 类型,比如调用标准库的 os.Stat 方法,返回的错误就是自定义类型: type PathError struct { Op string Path string Err error}func (e *PathError) Error() string { return e.Op + ' ' + e.Path + ': ' + e.Err.Error()} 暂时看不懂也没有关系,等学会了接口之后,再回过头来看这段代码,应该就豁然开朗了。 defer延迟函数调用,defer 后边会接一个函数,但该函数不会立刻被执行,而是等到包含它的程序返回时(包含它的函数执行了 return 语句、运行到函数结尾自动返回、对应的 goroutine panic),defer 函数才会被执行。 通常用于资源释放、打印日志、异常捕获等。
defer 语句经常成对出现,比如打开和关闭,连接和断开,加锁和解锁。 defer 语句在 return 语句之后执行。 package mainimport ( 'fmt')func main() { fmt.Println(triple(4)) // 12}func double(x int) (result int) { defer func() { fmt.Printf('double(%d) = %d\n', x, result) }() return x + x}func triple(x int) (result int) { defer func() { result += x }() return double(x)} 切勿在 for 循环中使用 defer 语句,因为 defer 语句不到函数的最后一刻是不会执行的,所以下面这段代码很可能会用尽所有文件描述符。
一种解决办法是将循环体单独写一个函数,这样每次循环的时候都会调用关闭函数。 for _, filename := range filenames { if err := doFile(filename); err != nil { return err }}func doFile(filename string) error { f, err := os.Open(filename) if err != nil { return err } defer f.Close()} defer 语句的执行是按调用 defer 语句的倒序执行。
输出: donesecondfirst panic 和 recover一般情况下,在程序里记录错误日志,就可以帮助我们在碰到异常时快速定位问题。 但还有一些错误比较严重的,比如数组越界访问,程序会主动调用 panic 来抛出异常,然后程序退出。 如果不想程序退出的话,可以使用 recover 函数来捕获并恢复。 感觉挺不好理解的,但仔细想想其实和 try-catch 也没什么区别。 先来看看两个函数的定义:
panic 参数类型是 interface{},所以可以接收任意参数类型,比如: panic(404)panic('network broken')panic(Error('file not exists')) recover 需要在 defer 函数中执行,举个例子:
输出: 捕获异常: ab继续执行c F() 中抛出异常被捕获,G() 还可以正常继续执行。如果 F() 没有捕获的话,那么 panic 会向上传递,直接导致 G() 异常,然后程序直接退出。 还有一个场景就是我们自己在调试程序时,可以使用 panic 来中断程序,抛出异常,用于排查问题。 这个就不举例了,反正是我们自己调试,怎么爽怎么来就行了。 总结错误处理在开发过程中至关重要,好的错误处理可以使程序更加健壮。而且将错误信息清晰地记录日志,在排查问题时非常有用。 Go 中使用 error 类型进行错误处理,还可以在此基础上自定义错误类型。 使用 defer 语句进行延迟调用,用来关闭或释放资源。 使用 panic 和 recover 来抛出错误和恢复。 使用 panic 一般有两种情况:
为了程序的健壮性,可以使用 recover 捕获错误,恢复程序运行。 文章中的脑图和源码都上传到了 GitHub,有需要的同学可自行下载。 地址: Go 专栏文章列表:
|
|
来自: 菌心说 > 《编程+、计算机、信息技术》