go语言20小时从入门到精通(九、异常解决)

作者 : 开心源码 本文共2592个字,预计阅读时间需要7分钟 发布时间: 2022-05-12 共199人阅读

9.1 error接口

Go语言引入了一个关于错误解决的标准模式,即error接口,它是Go语言内建的接口类型,该接口的定义如下:

type error interface {    Error() string}

Go语言的标准库代码包errors为客户提供如下方法:

package errorstype errorString struct {     text string }func New(text string) error {     return &errorString{text} }func (e *errorString) Error() string {     return e.text }

另一个可以生成error类型值的方法是调用fmt包中的Errorf函数:

package fmtimport "errors"func Errorf(format string, args ...interface{}) error {    return errors.New(Sprintf(format, args...))}

示例代码:

import (    "errors"    "fmt")func main() {    var err1 error = errors.New("a normal err1")    fmt.Println(err1) //a normal err1    var err2 error = fmt.Errorf("%s", "a normal err2")    fmt.Println(err2) //a normal err2}

函数通常在最后的返回值中返回错误信息:

import (    "errors"    "fmt")func Divide(a, b float64) (result float64, err error) {    if b == 0 {        result = 0.0        err = errors.New("runtime error: divide by zero")        return    }    result = a / b    err = nil    return}func main() {    r, err := Divide(10.0, 0)    if err != nil {        fmt.Println(err) //错误解决 runtime error: divide by zero    } else {        fmt.Println(r) // 使用返回值    }}

9.2 panic

在通常情况下,向程序使用方报告错误状态的方式可以是返回一个额外的error类型值。

但是,当遇到不可恢复的错误状态的时候,如数组访问越界、空指针引用等,这些运行时错误解引起painc异常。这时,上述错误解决方式显然就不适合了。反过来讲,在一般情况下,我们不应通过调用panic函数来报告普通的错误,而应该只把它作为报告致命错误的一种方式。当某些不应该发生的场景发生时,我们就应该调用panic。

一般而言,当panic异常发生时,程序会中断运行,并立即执行在该goroutine(可以先了解成线程,在中被推迟的函数(defer 机制)。随后,程序崩溃并输出日志信息。日志信息包括panic value和函数调用的堆栈跟踪信息。

不是所有的panic异常都来自运行时,直接调用内置的panic函数也会引发panic异常;panic函数接受任何值作为参数。
func panic(v interface{})

调用panic函数引发的panic异常:

func TestA() {    fmt.Println("func TestA()")}func TestB() {    panic("func TestB(): panic")}func TestC() {    fmt.Println("func TestC()")}func main() {    TestA()    TestB()//TestB()发生异常,中断程序    TestC()}

运行结果:

图片.png

内置的panic函数引发的panic异常:

func TestA() {    fmt.Println("func TestA()")}func TestB(x int) {    var a [10]int    a[x] = 222 //x值为11时,数组越界}func TestC() {    fmt.Println("func TestC()")}func main() {    TestA()    TestB(11)//TestB()发生异常,中断程序    TestC()}

运行结果:

图片.png

9.3 recover

运行时panic异常一旦被引发就会导致程序崩溃。这当然不是我们愿意看到的,由于谁也不能保证程序不会发生任何运行时错误。

不过,Go语言为我们提供了专用于“阻拦”运行时panic的内建函数——recover。它可以是当前的程序从运行时panic的状态中恢复并重新取得流程控制权。
func recover() interface{}

注意:recover只有在defer调用的函数中有效。

假如调用了内置函数recover,并且定义该defer语句的函数发生了panic异常,recover会使程序从panic中恢复,并返回panic value。导致panic异常的函数不会继续运行,但能正常返回。在未发生panic时调用recover,recover会返回nil。

示例代码:

func TestA() {    fmt.Println("func TestA()")}func TestB() (err error) {    defer func() { //在发生异常时,设置恢复        if x := recover(); x != nil {            //panic value被附加到错误信息中;          //并用err变量接收错误信息,返回给调用者。            err = fmt.Errorf("internal error: %v", x)        }    }()    panic("func TestB(): panic")}func TestC() {    fmt.Println("func TestC()")}func main() {    TestA()    err := TestB()    fmt.Println(err)    TestC()    /*        运行结果:        func TestA()        internal error: func TestB(): panic        func TestC()    */}

推迟调用中引发的错误,可被后续推迟调用捕获,但仅最后?个错误可被捕获:

func test() {    defer func() {        fmt.Println(recover())    }()    defer func() {        panic("defer panic")    }()    panic("test panic")}func main() {    test()    //运行结果:defer panic}

说明
1. 本站所有资源来源于用户上传和网络,如有侵权请邮件联系站长!
2. 分享目的仅供大家学习和交流,您必须在下载后24小时内删除!
3. 不得使用于非法商业用途,不得违反国家法律。否则后果自负!
4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解!
5. 如有链接无法下载、失效或广告,请联系管理员处理!
6. 本站资源售价只是摆设,本站源码仅提供给会员学习使用!
7. 如遇到加密压缩包,请使用360解压,如遇到无法解压的请联系管理员
开心源码网 » go语言20小时从入门到精通(九、异常解决)

发表回复