golang的异常处理

go语言是不支持异常的,go语言的设计者认为异常会被不成熟的程序员滥用,导致异常的处理过去复杂;go语言取消异常的一个替代办法是使用多返回值。

func foo(param1, param2, ...) (retval1, retval2, ...)

通常的函数实现里面,会使用一个error对象来表示是否成功,这其实类似于是否有异常发生

if val, err := foo(...); err != nil {
    // exception occured
}
// normal call flow

其实我个人觉得,像java语言的异常设计的已经比较合理了,完全可以保留使用,而不是丢弃;当然C++的异常是不完美的,是应该被禁用,因为C++的异常设计有本身的缺陷,主要是C++为了兼容C而导致的兼容性问题,历史包袱啊。

go语言的异常
go语言还是保留了一个异常处理的入口,那就是panic/recover/defer

作用如下

  • panic负责产生一个异常
  • defer里面t通过recover来捕获异常

panic是一个内置函数,原型定义如下:

func panic(v interface{})

recover也是一个内置函数,原型定义如下:

func recover() interface{}

panic的参数是一个interface类型,recover的返回值也是一个interface类型;其实panic()的参数正好就是recover()函数的返回值,就是这么传递过去的。

举例子来说:

package main

import (
    "fmt"
    "reflect"
)
func foo() {
    defer func() {
        if e := recover(); e != nil {
            fmt.Printf("recover type =[%v]\n\tvalue=[%v]\n", reflect.TypeOf(e), reflect.ValueOf(e))
        }
    }()
    panic(12)
}
func main() {
    foo()
}

运行结果:

recover type =[int]
        value=[12]

例子2:

package main

import (
    "fmt"
    "reflect"
)

func foo() {
    defer func() {
        if e := recover(); e != nil {
            fmt.Printf("recover type =[%v]\n\tvalue=[%v]\n", reflect.TypeOf(e), reflect.ValueOf(e))
        }
    }()
    panic(fmt.Errorf("meet an error"))
}

func main() {
    foo()
}

运行结果:

recover type =[*errors.errorString]
        value=[meet an error]

例子3:
这是一个异常链,也就是在一个function里面panic了,然后在上层caller里面捕获这个异常:

package main

import (
    "fmt"
    "reflect"
)

func foo() {
    panic("error in foo")
}

func main() {
    defer func() {
        if e := recover(); e != nil {
            fmt.Printf("recover type =[%v]\n\tvalue=[%v]\n", reflect.TypeOf(e), reflect.ValueOf(e))
        }
    }()

    foo()
}

运行

recover type =[string]
        value=[error in foo]

我们看到异常发生在foo()函数里面,但是捕获这个异常的是在main()函数里面。

    原文作者:CodingCode
    原文地址: https://www.jianshu.com/p/7a607eb22c0b
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞