博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
[golang note] 错误处理
阅读量:5218 次
发布时间:2019-06-14

本文共 6277 字,大约阅读时间需要 20 分钟。

错误处理


• 错误处理的标准模式

       golang错误处理的标准模式:error接口。

       golang函数如果要返回错误,规范上是将error作为多返回值中的最后一个,但这并非是强制要求。

▶ error接口

type error interface {       Error() string}

▶ 内置的error类型使用

▪ 语法如下

func 函数名(参数列表) (返回值列表, err error) {    // 函数体}

▪ 错误处理

       例如我们有一个这样的函数:

func Foo(param int) (n int, err error) {    // 函数体}

       调用函数时建议按如下方式处理错误:

n, err := Foo(0)if err != nil {    // 错误处理} else {    // 使用返回值n}

▪ 示例如下

package mainimport (    "errors"    "fmt")func divide(dividend float64, divisor float64) (result float64, err error) {    if divisor == 0 {        return -1, errors.New("除数为0")    }    return dividend / divisor, nil}func main() {    result, err := divide(1, 2)    if err != nil {        fmt.Println(err.Error())    } else {        fmt.Println("result =", result)    }    result, err = divide(1, 0)    if err != nil {        fmt.Println(err.Error())    } else {        fmt.Println("result =", result)    }}

▶ 自定义error类型使用

       golang错误处理支持自定义的error类型,只需要为自定义error类型实现Error接口即可。

▪ 语法如下

type CustomError struct {    ...}func (e *CustomError) Error() string {    // 函数体}

▪ 示例如下

package mainimport (    "fmt")type MathError struct {    Op   string    info string}func (e *MathError) Error() string {    return "Math operation " + e.Op + " error : " + e.info}func divide(dividend float64, divisor float64) (result float64, err error) {    if divisor == 0 {        return -1, &MathError{
"division", "divisor is zero"} } return dividend / divisor, nil}func main() { result, err := divide(1, 2) if err != nil { fmt.Println(err.Error()) } else { fmt.Println("result =", result) } result, err = divide(1, 0) if err != nil { fmt.Println(err.Error()) } else { fmt.Println("result =", result) }}

▪ 类型转换

       如果处理错误时需要获取详细信息,而不仅仅满足于打印一句错误信息,那就需要用到类型转换。

package mainimport (    "fmt")type MathError struct {    Op   string    info string}func (e *MathError) Error() string {    return "Math operation " + e.Op + " error : " + e.info}func divide(dividend float64, divisor float64) (result float64, err error) {    if divisor == 0 {        return -1, &MathError{
"division", "divisor is zero"} } return dividend / divisor, nil}func main() { result, err := divide(1, 0) if err != nil { // error类型转换为*MathError指针,因为接口定义传入类型对象为*MathError指针 // 如果接口定义时传入类型对象为MathError,那么这里的写法为err.(MathError) if e, ok := err.(*MathError); ok { fmt.Println(e.info) } } else { fmt.Println("result =", result) }}

资源释放


       在c++程序中,经常要注意内存指针、文件句柄、网络套接字等等资源的释放,特别需要注意其释放的时机。而golang使用defer

关键字和背后的内部机制简单地解决了资源释放的问题。

       defer关键字能保证其后的代码能在函数退出前调用。

       一个函数中可以存在多个defer语句,需要注意的是defer语句的调用是遵照先进后出的原则,即最后一个defer语句将最先被执行

       可以在defer后加一个匿名函数来进行复杂的清理工作。

• 简单的清理工作

▶ 语法如下

func 函数名(参数列表) (返回值列表) {    ...    // 资源申请    defer 清理函数    ...}

▶ 示例如下

package mainimport (    "io"    "os")func CopyFile(dst, src string) (w int64, err error) {    srcFile, err := os.Open(src)    if err != nil {        return    }    defer srcFile.Close()    dstFile, err := os.Create(dst)    if err != nil {        return    }    defer dstFile.Close()    return io.Copy(dstFile, srcFile)}func main() {    CopyFile("D:/2.txt", "D:/1.txt")}

▶ 先进后出规则

package mainimport (    "fmt")func Test() {    defer fmt.Println(1)    defer fmt.Println(2)    defer fmt.Println(3)}func main() {    Test()}

• 复杂的清理工作

▶ 语法如下

func 函数名(参数列表) (返回值列表) {    ...    // 资源申请    defer func() {        // 复杂的清理工作    } ()    ...}

▶ 示例如下

package mainimport (    "fmt"    "io"    "os")func CopyFile(dst, src string) (w int64, err error) {    srcFile, err := os.Open(src)    if err != nil {        return    }    defer func() {        fmt.Println("close file :", src)        srcFile.Close()    }()     dstFile, err := os.Create(dst)    if err != nil {        return    }    defer func() {        fmt.Println("close file :", dst)        dstFile.Close()    }()    return io.Copy(dstFile, srcFile)}func main() {    CopyFile("D:/2.txt", "D:/1.txt")}

异常处理


       一些高级语言中一般提供类似try...catch...finally...的语法,用于捕获异常。golang提供panicrecover两个关键字用于异常处理。

• panic

       panic在golang中是一个内置函数,接收一个interface{}类型的值作为参数:

func panic(interface{}) {    ...}

       当一个函数执行过程中调用panic函数时,函数执行流程将立即终止,但panic之前的defer关键字延迟执行的语句将正常执行,之后该函数将返回到上层调用函数,并逐层向上执行panic流程,直至函数所属的goroutine中所有正在执行函数终止。错误信息将被报告,包括在调用panic()函数时传入的参数。下面用一个示例说明:

package mainimport (    "fmt")func MyFunc1() {    defer fmt.Println("MyFunc1 defer 1")    panic("MyFunc1 panic test")    defer fmt.Println("MyFunc1 defer 2")}func MyFunc2() {    defer fmt.Println("MyFunc2 defer 1")    MyFunc1()    defer fmt.Println("MyFunc2 defer 2")}func main() {    MyFunc2()}

       程序输出如下:

      

• recover

       recover在golang中是一个内置函数,返回一个interface{}类型的值作为参数:

func recover() interface{} {    ...}

       panic函数触发后不会立即返回,而是先defer,再返回。如果defer的时候,有办法将panic捕获到,然后及时进行异常处理,并阻止panic传递,那处理机制就完善了。因此golang提供了recover内置函数,用于捕获panic并阻止其向上传递。需要注意的是,recover之后,逻辑并不会恢复到panic处,函数还是会在defer之后返回,但是所属goroutine将不会退出。

▶ 本层函数处理

package mainimport (    "fmt")func MyFunc1() {    defer func() {        fmt.Println("MyFunc1 defer 1")        if r := recover(); r != nil {
fmt.Println("Runtime error caught :", r) } }() panic("MyFunc1 panic test") fmt.Println("MyFunc1 defer 2")}func MyFunc2() { defer fmt.Println("MyFunc2 defer 1") MyFunc1() defer fmt.Println("MyFunc2 defer 2")}func main() { MyFunc2()}

       程序输出如下:

      

▶ 上层函数处理

package mainimport (    "fmt")func MyFunc1() {    defer fmt.Println("MyFunc1 defer 1")    panic("MyFunc1 panic test")    fmt.Println("MyFunc1 defer 2")}func MyFunc2() {    defer func() {
fmt.Println("MyFunc1 defer 2") if r := recover(); r != nil {
fmt.Println("Runtime error caught :", r) } }() MyFunc1() defer fmt.Println("MyFunc2 defer 2")}func main() { MyFunc2()}

       程序输出如下:

      

• 模拟try...catch...语法

▶ 语法如下

func Try(f func(), handler func(interface{})) {    defer func() {        if err := recover(); err != nil {            handler(err)        }    }()    f()}

▶ 示例如下

package mainimport (    "fmt")func Try(f func(), handler func(interface{})) {    defer func() {        if err := recover(); err != nil {            handler(err)        }    }()    f()}func main() {    Try(func() {        panic("main panic")    }, func(e interface{}) {        fmt.Println(e)    })}

 

转载于:https://www.cnblogs.com/heartchord/p/5236091.html

你可能感兴趣的文章
java正则
查看>>
结对编程学习fault、error、failure三种状态
查看>>
restful规范
查看>>
html页面的meta标签
查看>>
大道至简第二章读后感
查看>>
PHP程序员的技术成长规划
查看>>
Sublime Text的使用手册
查看>>
(中等) POJ 2886 Who Gets the Most Candies? , 反素数+线段树。
查看>>
python 制作一对一聊天
查看>>
第七节(隐藏、显示、切换,滑动,淡入淡出,以及动画)
查看>>
从android aidl理解Proxy/stub模式
查看>>
测试一个对象是否是类字符串
查看>>
3.Longest Substring Without Repeating Characters
查看>>
网络对抗技术实验1
查看>>
大端与小端
查看>>
批量添加用户,并设置8位随机密码(禁止使用for,while等循环)
查看>>
ssh密钥讲解
查看>>
将博客搬至CSDN
查看>>
ZH奶酪:Ubuntu 14.04安装LAMP(Linux,Apache,MySQL,PHP)
查看>>
重温Javascript(三)-继承
查看>>