Golang学习笔记之错误处理error、panic (抛出错误),recover(捕获错误)

栏目: Go · 发布时间: 6年前

内容简介:错误表示程序中出现了异常情况。Go 语言通过内置的错误接口提供了非常简单的错误处理机制。• error类型是go语言的一种内置类型,使用的时候不用特定去import因为它本质上是一个接口在go中处理错误的惯用方式是将返回的错误与nil进行比较。零值表示没有发生错误,而非零值表示存在错误。

一、error

错误表示程序中出现了异常情况。Go 语言通过内置的错误接口提供了非常简单的错误处理机制。

• error类型是 go 语言的一种内置类型,使用的时候不用特定去import因为它本质上是一个接口

error类型是一个接口类型,这是它的定义:

type error interface {
    Error() string
}

(1)一个例子理解error

package main
import (
    "fmt"
    "os"
)
func main() {
    //试图打开一个并不存在的文件,这将会返回一个error
    f, err := os.Open("/test.txt")
    if err != nil {
        fmt.Println(err) //no such file or directory
        return
    }
    fmt.Println(f.Name(), "opened successfully")
}

在go中处理错误的惯用方式是将返回的错误与nil进行比较。零值表示没有发生错误,而非零值表示存在错误。

(2)错误定制

上面也看到了error 有了一个签名为 Error() string 的方法。所有实现该接口的类型都可以当作一个错误类型。

第一、通过errors包去订制error

函数原型: func New(text string) error
使用字符串创建一个错误可以认为是New(fmt.Sprintf(...))。

import  "errors"    //使用errors必须import "errors"包
error := errors.New("Myerror")
if error != nil {
    fmt.Print(err)    //Myerror
}

demo

package main
import (
    "errors"
    "fmt"
    "math"
)
func circleArea(radius float64) (float64, error) {
    if radius < 0 {
        //使用字符串创建一个错误
        return 0, errors.New("Area calculation failed, radius is less than zero")
    }
    return math.Pi * radius * radius, nil
}
func main() {
    radius := -20.0
    area, err := circleArea(radius)
    if err != nil {
        fmt.Println(err)
        return
    }
    fmt.Printf("Area of circle %0.2f", area)
}

第二种、通过fmt.Errorf()去订制

函数原型: func Errorf(format string, a ...interface{}) error
Errorf根据format参数生成格式化字符串并返回一个包含该字符串的错误。

err := fmt.Errorf("error")
if err != nil {
    fmt.Print(err)
}

就不贴demo了

只需要把circleArea里if语句的返回值改为

return 0, fmt.Errorf("Area calculation failed, radius %.2f is less than zero",radius)

第三种、使用结构体和字段来定制

type MyError struct {
err error 
}
//订制Error()
func (e MyError) Error() string {
    return e.err.Error()
}
func main() {
   err:=MyError{
        errors.New("error"),
   }
   fmt.Println(err.Error())
}

demo

package main
import (
    "fmt"
    "math"

)
type areaError struct {
    err    string
    radius float64
}
func (e *areaError) Error() string {
    return fmt.Sprintf("radius %0.2f:%s", e.radius, e.err)
}

func (e *areaError) IsRadiusNagative() bool {
    return e.radius < 0

}
func circleArea(radius float64) (float64, error) {
    if radius < 0 {
        return 0, &areaError{"Radius is negative", radius}
    }
    return math.Pi * radius * radius, nil
}
func main() {
    s, err := circleArea(-20)
    if err != nil {
        //将错误转换为具体的类型
        if err, ok := err.(*areaError); ok {
            fmt.Printf("Radius %.2f is less than zero", err.radius)
            return
        }
        fmt.Println(err)
        return
    }
    fmt.Println(s)
}

二、panic (抛出错误)和recover(捕获错误)

golang中没有try ... catch...这类异常捕获语句,但是提供了panic和recover内建函数,用于抛出异常以及异常的捕获。

• panic、 recover 参数类型为 interface{},因此可抛出任何类型对象。

• 如果程序出现了致命的错误,导致整个程序无法进行下去,golang提供了panic函数,用来实现程序的退出。

• 当程序发生 panic 时,使用 recover 可以重新获得对该程序的控

制。

• 不是所有的panic异常都来自运行时,直接调用内置的panic函数也会引发panic异常

• panic函数接受任何值作为参数。

(1)panic的使用

①延迟调⽤中引发的错误,可被后续延迟调⽤捕获,但仅最后⼀个错误可被捕获。

func test() {
defer func() {
    fmt.Println(recover())
}()
defer func() {
    panic("defer panic")
}()
    panic("test panic")
}
func main() {
    test()    //defer panic
}

②当函数发生 panic 时,它会终止运行,在执行完所有的延迟函数后,程序控制返回到该函数的调用方。这样的过程会一直持续下去,直到当前协程的所有函数都返回退出,然后程序会打印出 panic 信息,接着打印出堆栈跟踪,最后程序终止。

** 如果函数没有 panic,调用 recover 函数不会获取到任何信息,也不会影响当前进程。**

demo

package main
import (
    "fmt"
)
func fullName(firstName *string, lastName *string) {
    if firstName == nil {
        panic("Firsr Name can't be null")
    }
    if lastName == nil {
        panic("Last Name can't be null")
    }
    fmt.Printf("%s %s\n", *firstName, *lastName)
    fmt.Println("returned normally from fullName")
}
func test(){
    defer fmt.Println("deferred call in test")
    firName := "paul"
    fullName(&firName, nil)
}
func main() {
    defer fmt.Println("deferred call in main")
    test()
    fmt.Println("returned normally from main")
}

输出

Golang学习笔记之错误处理error、panic (抛出错误),recover(捕获错误)

(2)recover的使用

如果 goroutine 没有 panic,那调用 recover 函数会返回 nil。
捕获函数 recover 只有在延迟调⽤内直接调⽤才会终⽌错误,否则总是返回 nil。任何未捕获的错误都会沿调⽤堆栈向外传递。

修改一下上面的例子使用recover来捕获异常

package main
import (
    "fmt"
)
func recoverName()  {
    if r := recover(); r != nil{
        fmt.Println("recovered from ",r)
    }
}
func fullName(firstName *string, lastName *string) {
    defer recoverName()
    if firstName == nil {
        panic("Firsr Name can't be null")
    }
    if lastName == nil {
        panic("Last Name can't be null")
    }
    fmt.Printf("%s %s\n", *firstName, *lastName)
    fmt.Println("returned normally from fullName")
}
func test(){
    defer fmt.Println("deferred call in test")
    firName := "paul"
    fullName(&firName, nil)
}
func main() {
    defer fmt.Println("deferred call in main")
    test()
    fmt.Println("returned normally from main")
}

输出为:

Golang学习笔记之错误处理error、panic (抛出错误),recover(捕获错误)

当发生panic之后,当前函数使用了recover,则捕获了这个错误,交给上一层调用者,正常执行剩下的代码;如果当前函数没有使用recover,调用者使用了recover,则属于调用者捕获了错误,将权限交给调用者的调用者,之后正常执行

recover函数捕捉了错误,但是这时我们并不容易发现错误的位置,那么可以在实现了recover函数的函数中使用debug.PrintStack(),这样就可以输出错误出现的函数,使用这个最先显示的行数是系统的,也就是stack.go包下的具体位置,这个会有两行,然后是调用debug.PrintStack()的地方,这个是自己写的函数,再然后就是系统的panic.go包,因为出错的时候的会调用这个包里面的函数,然后就是具体的错误位置了

函数原型:

func Stack() []byte

Stack 返回格式化的go程的调用栈踪迹。 对于每一个调用栈,它包括原文件的行信息和PC值;对go函数还会尝试获取调用该函数的函数或方法,及调用所在行的文本。

func PrintStack()

PrintStack将Stack返回信息打印到标准错误输出。

demo

import (
"fmt"
"runtime/debug"
)
func r() {
    if r := recover(); r != nil {
    fmt.Println("Recovered", r)
    debug.PrintStack()
    }
}

以上所述就是小编给大家介绍的《Golang学习笔记之错误处理error、panic (抛出错误),recover(捕获错误)》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Web Scalability for Startup Engineers

Web Scalability for Startup Engineers

Artur Ejsmont / McGraw / 2015-6-23 / USD 34.81

Design and build scalable web applications quickly This is an invaluable roadmap for meeting the rapid demand to deliver scalable applications in a startup environment. With a focus on core concept......一起来看看 《Web Scalability for Startup Engineers》 这本书的介绍吧!

随机密码生成器
随机密码生成器

多种字符组合密码

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具