您的位置:首页 > 编程语言 > Go语言

Golang从入门到精通(二十一):Golang错误处理之panic-recover

2017-12-14 11:10 495 查看
Go 语言没有像 Java 和 .NET 那样的
try/catch
异常机制:不能执行抛异常操作。但是有一套
defer-panic-and-recover
机制。

Golang中引入两个内置函数panic和recover来触发和终止异常处理流程,同时引入关键字defer来延迟执行defer后面的函数。一直等到包含defer语句的函数执行完毕时,延迟函数(defer后的函数)才会被执行,而不管包含defer语句的函数是通过return的正常结束,还是由于panic导致的异常结束。你可以在一个函数中执行多条defer语句,它们的执行顺序与声明顺序相反。

panic介绍

当发生像数组下标越界或类型断言失败这样的运行错误时,Go 运行时会触发运行时
panic
,伴随着程序的崩溃抛出一个
runtime.Error
接口类型的值。这个错误值有个
RuntimeError()
方法用于区别普通错误。

panic 可以直接从代码初始化:当错误条件(我们所测试的代码)很严苛且不可恢复,程序不能继续运行时,可以使用 panic 函数产生一个中止程序的运行时错误。
panic
接收一个做任意类型的参数,通常是字符串,在程序死亡时被打印出来。Go 运行时负责中止程序并给出调试信息。

panic()
是一个内建函数,可以中断原有的控制流程,进入一个令人
panic
(恐慌即Java中的异常)的流程中。当函数调用
panic
时,函数的执行会被中断,最简单的
panic
示例代码如下:

package main

import "fmt"

func main() {
fmt.Println("Starting the program")
panic("A severe error occurred: stopping the program!")
fmt.Println("Ending the program")
}


这段代码的打印结果因人而异,笔者win10 64位+go1.7.5的环境下打印结果如下:

Starting the program
panic: A severe error occurred: stopping the program!

goroutine 1 [running]:
panic(0x4951e0, 0xc0420062c0)
D:/Go/src/runtime/panic.go:500 +0x1af
main.main()
E:/testcode/test.go:7 +0xf6
exit status 2


注意:一定要记住,应当把
panic
作为最后的手段来使用,也就是说,你的代码中应当没有或者很少有
panic
的东西。这是个强大的工具,请明智谨慎地使用它。

recover介绍

recover
是一个内建的函数,可以让进入令人恐慌的流程中的goroutine恢复过来。
recover
仅在延迟函数中有效。在正常的执行过程中,调用
recover
会返回
nil
,并且没有其它任何效果。如果当前的
goroutine
陷入
panic
,调用
recover
可以捕获到
panic
的输入值,并且恢复正常的执行。

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

从程序栈的角度来讲,
panic
会导致栈被展开直到
defer
修饰的
recover()
被调用或者程序中止。

一个展示
panic
defer
recover
怎么结合使用的完整例子如下:

package main

import (
"fmt"
)

func badCall() {
panic("bad end")
}

func test() {
defer func() {
if e := recover(); e != nil {
fmt.Printf("Panicing %s\n", e)
}
}()
badCall()
fmt.Printf("After bad call\n")
}

func main() {
fmt.Printf("Calling test\n")
test()
fmt.Printf("Test completed\n")
}
//output
/*
Calling test
Panicing bad end
Test completed
*/


错误处理机制总结

Go 语言的错误处理流程:当一个函数在执行过程中出现了异常或遇到
panic()
,正常语句就会立即终止,然后执行
defer
语句,再报告异常信息,最后退出
goroutine
。如果在
defer
中使用了
recover()
函数,则会捕获错误信息,使该错误信息终止报告。

这里结合上一关卡所学的
error
内容,实现一个自定义的
Error()
方法,并结合
panic
recover
,集中展示下
Go
语言的错误处理机制:

package main

import (
"fmt"
)

//自定义错误类型
type ArithmeticError struct {
error
}

//重写Error()方法
func (this *ArithmeticError) Error() string {
return "自定义的error,error名称为算数不合法"
}

//定义除法运算函数***这里与本文中第一幕①error接口的例子不同
func Devide(num1, num2 int) int {
if num2 == 0 {
panic(&ArithmeticError{}) //当然也可以使用ArithmeticError{}同时recover等到ArithmeticError类型
} else {
return num1 / num2
}
}
func main() {
var a, b int
fmt.Scanf("%d %d", &a, &b)

defer func() {
if r := recover(); r != nil {
fmt.Printf("panic的内容%v\n", r)
if _, ok := r.(error); ok {
fmt.Println("panic--recover()得到的是error类型")
}
if _, ok := r.(*ArithmeticError); ok {
fmt.Println("panic--recover()得到的是ArithmeticError类型")
}
if _, ok := r.(string); ok {
fmt.Println("panic--recover()得到的是string类型")
}
}
}()

rs := Devide(a, b)
fmt.Println("结果是:", rs)
}


用 go run file.go执行该文件,输入5 2得:

$ go run test.go
5 2
结果是: 2


输入5 0得:

$ go run test.go
5 0
panic的内容自定义的error,error名称为算数不合法
panic--recover()得到的是error类型
panic--recover()得到的是ArithmeticError类型
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息