linuxea:go错误处理和延迟执行(34)

marksugar
2020-11-23 / 0 评论 / 783 阅读 / 正在检测是否收录...
温馨提示:
本文最后更新于2020年11月23日,已超过298天没有更新,若内容或图片失效,请留言反馈。

go语言通过error接口实现错误处理的标准模式,在go中山没有异常的,可以通过返回值信息告诉调用者是否发生了错误。一般而言,我们需要定义返回错误的值,如果没有定义错误处理,那就会抛出错误信。
请输入图片描述

1.错误处理errors.New()

  • error接口
    通常error接口,通过errors包中的errors.New()fmt.Errorf方法进行创建。
  • error

error如果没有错误就会返回nil,如果有就返回创建的错误信息

我们先看没有错误处理的情景,比如下面这段代码:

package main
import "fmt"
func division(a,b int) int {
    return a / b
}
func main(){
    fmt.Println(division(9,3))
    fmt.Println(division(1,0))
}

运行

[root@linuxea.com /opt/Golang/work3]# go run error1.go
3
panic: runtime error: integer divide by zero

goroutine 1 [running]:
main.division(...)
    /opt/Golang/work3/error1.go:4
main.main()
    /opt/Golang/work3/error1.go:8 +0x88
exit status 2
  • errors.New()

我们通过errors包中的errors.New()函数来创建

我们定义返回值的错误类型,如下:

首先判断,行参b等于0就返回-1,并且返回errors.New("division by zero")。反之返回a除以b,和nil

func division(a,b int) (int,error) {
    if b == 0 {
        return -1,errors.New("division by zero")
    }
    return a / b,nil
}

在main函数中,也需要做处理,division函数中返回了两个返回值,main中接收,在做处理,如果返回的是nil,说明没有错误,直接打印返回的int,否则就将接收的errors返回值打印出来

func main(){
    fmt.Println(division(9,3))
    if v,err := division(1,0);err != nil{
        fmt.Println(err)
    }else {
        fmt.Println(v)
    }
}

代码块

package main
import (
    "fmt"
    "errors"
)
func division(a,b int) (int,error) {
    if b == 0 {
        return -1,errors.New("division by zero")
    }
    return a / b,nil
}
func main(){
    fmt.Println(division(9,3))
    if v,err := division(1,0);err != nil{
        fmt.Println(err)
    }else {
        fmt.Println(v)
    }
}

运行

[root@linuxea.com /opt/Golang/work3]# go run error.go
3 <nil>
division by zero
  • fmt.Errorf()

除了errors.New还有在fmt包中的Errorf函数。我们打印下它的类型

[root@linuxea.com /opt/Golang/work3]# cat error2.go
package main
import "fmt"
func main(){
    e := fmt.Errorf("Error: %s","division by zero")
    fmt.Printf("%T,%v\n",e,e)
}

运行

[root@linuxea.com /opt/Golang/work3]# go run error2.go 
*errors.errorString,Error: division by zero

2.延迟执行defer

在很多时候,不管程序异常或者正常,我们都希望它执行一些代码。就需要延迟执行

  • defer

defer会在函数退出的时候执行。

  • 示例

打印两个语句,分别用defer和不用defer。如下:

通常,defer会跟上一个匿名函数调用

    defer func(){
        fmt.Println("defer")
    }()

我们在加上一个fmt.Println("main")

package main
import "fmt"
func main(){
    defer func(){
        fmt.Println("defer")
    }()
    fmt.Println("main")
}    

运行

[root@linuxea.com /opt/Golang/work3]# go run defer.go
main
defer

可以发现,main先被打印,而后再打印的defer

  • 多个defer

如果此刻有多个defer,打印的顺序将会是从后往前执行,如下:

  • 示例

分别打印defer one,defer twomain

package main
import "fmt"
func main(){
    defer func(){
        fmt.Println("defer two")
    }()
    defer func(){
        fmt.Println("defer one")
    }()    
    fmt.Println("main")
}

运行

[root@linuxea.com /opt/Golang/work3]# go run defer1.go
main
defer one
defer two

这遵循栈规则,先进后出。或者说defer是从下往上执行的顺序。

3.panic与recover错误处理

go语言提供panic和recover函数用于处理运行时的错误,当调用panic抛出错误,中断原有的流程控制,常用于不可修复性错误。recover函数用于终止错误处理流程,仅在defer语句的函数中有效,用于截取错误处理流程,recover只能捕获到最后一个错误

  • panic示例

我们在panic前后打印start和end

[root@linuxea.com /opt/Golang/work3]# cat panic.go
package main
import "fmt"
func main(){
    fmt.Println("main start")
    panic("error")
    fmt.Println("main end")
}

运行

[root@linuxea.com /opt/Golang/work3]# go run panic.go
main start
panic: error

goroutine 1 [running]:
main.main()
    /opt/Golang/work3/panic.go:5 +0x96
exit status 2

可以看到panic后面的print是没有执行的。在panic处就结束了。

  • recover

recover函数一般用于做恢复的,主动处理panic的错误,必须用于defer中。

但是和之前不同的是,使用了recover后,发生错误后返回的是一个panic error信息

  • 示例

recover是string类型的一个error,所以我们可以使用if判断是否等于nil或者不等于nil

如果不等于nil,那说明有错误,就可以抛出错误。这里手动加的panic("the is error")

package main
import "fmt"
func main(){
    defer func(){
        if err := recover(); err != nil{
            fmt.Println(err)
        }
    }()
    fmt.Println("start")
    panic("the is error")
    fmt.Println("end")
}

运行

[root@linuxea.com /opt/Golang/work3]# go run recover.go
start
the is error

如果没有panic错误,就不会执行recover()

[root@linuxea.com /opt/Golang/work3]# cat recover.go
package main
import "fmt"
func main(){
    defer func(){
        if err := recover(); err != nil{
            fmt.Println(err)
        }
    }()
    fmt.Println("start")
    fmt.Println("end")
}

运行

[root@linuxea.com /opt/Golang/work3]# go run recover.go
start
end
  • 示例2

在其他函数中也可以直接这样抓取panic错误,如下:

func test(){
    defer func(){
        if err := recover(); err != nil{
            fmt.Println(err)
        }
    }()    
    panic("the test error")
}

或者返回一个error信息

首先定义一个error返回值,如果发生panic错误,就通过recover将值赋值给err,通过return返回

func test() (err error) {
    defer func(){
        if er := recover(); er != nil{
            err = fmt.Errorf("%v",er)
        }
    }()    
    panic("the test error")
    return
}

而后在main中,因为test有返回值,这里需要as接收,而后打印即可。

func main(){
    as := test()
    fmt.Println(as)
}

如下:

package main
import "fmt"
func test() (err error) {
    defer func(){
        if er := recover(); er != nil{
            err = fmt.Errorf("%v",er)
        }
    }()    
    panic("the test error")
    return
}
func main(){
    as := test()
    fmt.Println(as)
}

运行

[root@linuxea.com /opt/Golang/work3]# go run testerr.go
the test error
0

评论 (0)

取消