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

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() 被调用或者程序中止。

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

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()方法,并结合panicrecover,集中展示下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类型
  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值