zoukankan      html  css  js  c++  java
  • go语言入门(8)异常处理

    1,error接口

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

    type error interface {
        Error() string
    }

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

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

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

    package fmt
    import "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) // 使用返回值
        }
    }

    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()
    }

    内置的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()
    }

    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
    }
  • 相关阅读:
    (最小生成树) 畅通工程再续 -- HDU --1875
    (最小生成树)Jungle Roads -- HDU --1301
    (最小生成树 )还是畅通工程 -- HDU--1233
    不同版本的 IIS 中使用 ASP.NET MVC(C#)【转】
    我们应当怎样做需求分析【转】
    C# DataTable几个常用的查询表达式【转】
    C# DataTable转实体 通用方法【转】
    C# 如何利用反射来加载程序集,并调用程序集中有关类的方法【转】
    IEnumerable和IEnumerator 详解 【转】
    循环对XML文档添加Attribute以及移除Element 【转】
  • 原文地址:https://www.cnblogs.com/xdyixia/p/11895748.html
Copyright © 2011-2022 走看看