亲宝软件园·资讯

展开

一文详细谈谈GoLang的panic和error

渣渣帅 人气:0

前言

首先说一下: 错误指的是可能出现问题的地方出现了问题。如打开件失败,这种情况在意料之中 。异常指的是不应该出现问题的地方出现了问题。如引用了空指针,这种情况在意料之外

Go 提供两种错误处理方式

1. panic

Go的类型系统会在编译时捕获很多错误,但有些错误只能在运行时检查,如数组访问越界、空指针引用等。这些运行时错误会引起painc异常。

一般而言,当panic异常发生时,程序会中断运行,并立即执行在该goroutine(可以先理解成线程)中被延迟的函数(defer 机制)。随后,程序崩溃并输出日志信息。日志信息包括panic value和函数调用的堆栈跟踪信息。panic value通常是某种错误信息。对于每个goroutine,日志信息中都会有与之相对的,发生panic时的函数调用堆栈跟踪信息。通常,我们不需要再次运行程序去定位问题,日志信息已经提供了足够的诊断依据。因此,在我们填写问题报告时,一般会将panic异常和日志信息一并记录。不是所有的panic异常都来自运行时,直接调用内置的panic函数也会引发panic异常;panic函数接受任何值作为参数。当某些不应该发生的场景发生时,我们就应该调用panic。虽然Go的panic机制类似于其他语言的异常,但panic的适用场景有一些不同。由于panic会引起程序的崩溃,因此panic一般用于严重错误,如程序内部的逻辑不一致。

panic可以手工调用,但是 Go 官方建议尽量不要使用panic,每一个异常都应该用 error 对象捕获。如果异常出现了,但没有被捕获并恢复,Go 程序的执行就会被终止,即便出现异常的位置不在主 Goroutine 中也会这样。

总结来说:

panic是一个严重错误机制,它会导致程序终止,并依次逆序执行 panic 所在函数可能存在的 defer 函数列表,然后返回该函数的调用方。recover 内置函数可用于捕获 panic,重新恢复程序正常执行流程,但是 recover 函数只有在 defer 内部使用才有效

此外,当 panic() 触发的宕机发生时, panic() 后面的代码将不会被运行,但是在 panic() 函数前面已经运行过的 defer 语句依然会在宕机发生时发生作用

2. recover

1. recover 是一个 Go 语言的内建函数,可以让进入宕机流程中的 goroutine 恢复过来。

2. 用来控制一个goroutine的panicking行为,捕获panic,从而影响应用的行为

3. 一般的调用建议

a). 在defer函数中,通过recever来终止一个gojroutine的panicking过程,从而恢复正常代码的执行

b). 可以获取通过panic传递的error

简单来讲:go中可以抛出一个panic的异常,然后在defer中通过recover捕获这个异常,然后正常处理。

4. 在正常的执行过程中,调用 recover 会返回 nil 并且没有其他任何效果;

注意:利用recover处理panic指令,defer必须在panic之前声明,否则当panic时,recover无法捕获到panic.

总结来说 Go 语言没有异常系统,其使用 panic 触发宕机类似于其他语言的抛出异常, recover 的宕机恢复机制就对应其它语言中的 try/catch 机制。

panic 和 recover 的关系

panic 和 recover 的组合有如下特性:

有 panic 没 recover ,程序宕机。

有 panic 也有 recover ,程序不会宕机,执行完对应的 defer 后,从宕机点退出当前函数后继续执行。

注意:在 panic 触发的 defer 函数内,可以继续调用 panic ,进一步将错误外抛,直到程序整体崩溃。如果想在捕获错误时设置当前函数的返回值,可以对返回值使用命名返回值方式直接进行设置。

示例:

package main
 
func test() {
	defer func() {
		if err := recover(); err != nil { // recover 捕获错误。
			println(err.(string)) // 将 interface{} 转型为具体类型。
		}
	}()
	panic("panic error!")	// panic 抛出错误
}
func main() {
	test()
}

3. error

go中的错误处理,是通过返回值的形式来出来,要么你忽略,要么你处理(处理也可以是继续返回给调用者),对于golang这种设计方式,我们会在代码中写大量的if判断,以便做出决定。

对于err如果是nil就代表没有错误,如果不是nil就代表程序出问题了,需要对错误进行处理了。

示例:

func main() {
	conent,err:=ioutil.ReadFile("filepath")
	if err !=nil{
		//错误处理
	}else {
		fmt.Println(string(conent))
	}
}

此外,error类型是go语言的一种内置类型,使用的时候不用特定去import,他本质上是一个接口,

 type error interface{
  Error() string //Error()是每一个订制的error对象需要填充的错误消息,可以理解成是一个字段Error
}

总结

加载全部内容

相关教程
猜你喜欢
用户评论