本篇将开始error、defer、panic和recover机制的学习。 关键字defer⽤于延迟一个函数或者方法(或者当前所创建的匿名函数)的执行。defer语句只能出现在函数或方法的内部。
error
error接口
错误是指程序中出现不正常的情况,从而导致程序无法正常执行。假设尝试打开一个文件,文件系统中不存在这个文件。这是一个异常情况,它表示为一个错误。
Go 语言通过内置的错误类型提供了非常简单的错误处理机制。即error接口,该接口的定义如下:
error本质上是一个接口类型,其中包含一个Error()方法,错误值可以存储在变量中,通过函数中返回。它必须是函数返回的最后一个值。
在Go语言中处理错误的方式通常是将返回的错误与nil进行比较。nil值表示没有发生错误,而非nil值表示出现错误。如果不是nil,需打印输出错误。
创建error对象
结构体只要实现了Error() string这种格式的,就代表实现了该错误接口,返回值为错误的具体描述。通常程序会发生可预知的错误,所以Go语言errors包对外提供了可供用户自定义的方法,errors包下的New()函数返回error对象,errors.New()创建新的错误。errors包内代码如下:
Go语言的errors.go源码定义了一个结构体,名为errorString,它拥有一个Error()的方法,实现了error接口,同时该包向外暴露了一个New()函数,该函数参数为字符串,返回值为error类型。
fmt包下的Errorf()函数返回error对象,fmt包下的Errorf()函数本质上还是调用errors.New()。使用格式如下。
自定义错误
自定义错误的实现步骤如下。
定义一个结构体,表示自定义错误的类型;
让自定义错误类型实现error接口的方法 :Error() string;
定义一个返回error的函数。根据程序实际功能而定。
自定义错误的使用示例如例所示。
defer
关键字defer用于延迟一个函数或者方法(或者当前所创建的匿名函数)的执行。defer语句只能出现在函数或方法的内部。
Ø 函数中使用defer
在函数中可以添加多个defer语句。如果有很多调用defer,当函数执行到最后时,这些defer语句会按照逆序执行(报错的时候也会执行),最后该函数返回。
defer执行顺序如例所示。
defer语句经常被用于处理成对的操作,如打开、关闭、连接、断开连接、加锁、释放锁。特别是在打开资源的操作时,遇到错误需要提前返回,在返回前需要关闭相应的资源,不然很容易造成资源泄露等问题。
defer在函数中使用如例所示。
Ø 方法中使用defer
延迟并不局限于函数。延迟一个方法调用也是完全合法的。
使用方式如例所示。
Ø defer参数
延迟函数的参数在执行延迟语句时被执行,而不是在执行实际的函数调用时执行。
详情如例所示。
Ø 堆栈的推迟
当一个函数有多个延迟调用时,它们被添加到一个堆栈中,并在(Last In First Out,LIFO)后进先出的顺序中执行。详情参见所示。
panic和recove机制
Ø panic
Go语言追求简洁优雅,Go没有像Java那样的 try...catch...finally 异常处理机制。Go语言设计者认为,将异常与流程控制混在一起会让代码变得混乱。
panic,让当前的程序进入恐慌,中断程序的执行。或者说,panic()是一个内建函数,可以中断原有的控制流程,进入一个令人恐慌的流程中。参见所示。
在通常情况下,向程序使用方报告错误状态的方式可以是返回一个额外的error类型值。但是,当遇到不可恢复的错误状态的时候,如数组访问越界、空指针引用等,这些运行时错误会引起painc异常。这时,上述错误处理方式显然就不适合了。
在一般情况下,不应通过调用panic函数来报告普通的错误,而应该只把它作为报告致命错误的一种方式。当某些不应该发生的场景发生时调用panic。
内置的panic函数引发的panic异常如例所示。
Ø recover
panic异常一旦被引发就会导致程序崩溃。这当然不是程序员愿意看到的,因为谁也不能保证程序不会发生任何运行时错误。不过,Go语言为开发者提供了专用于“拦截”运行时panic的内建函数recover。
recover()可以让进入令人恐慌的流程中的Goroutine(可当做线程理解,后续章节会详细讲解)恢复过来并重新获得流程控制权。
需要注意的是,recover()让程序恢复,必须在defer函数中执行。换言之,recover仅在延迟函数(defer)中有效。
在正常 的执行过程中,调用recover()会返回nil,并且没有其他任何效果。如果当前的Goroutine陷入恐慌,调用 recover()可以捕获到panic()的输入值,使程序恢复正常运行。
rocover使用方式如例所示。
切记,开发者应该把它作为最后的手段来使用,换言之,开发者的代码中尽量少有或者没有panic异常。
小结:
主要介绍了Go语言中的错误处理、异常处理机制。在实际开发中要尽量多使用错误判断,以便开发者在程序出错的时候定位问题。
PS:梳理了Go语言异常处理的error、defer、panic和recover机制的笔记和视频教程,若有不懂或者想要全部笔记的可私信交流哦~