您的位置 首页 golang

【go】异常处理

知识点:
1.异常处理 defer,panic,recover
2.error
3.自定义错误类型


异常处理:

在异常处理方面,Go语言不像其他语言,使用try..catch.. finall…, 而使用defer, panic, recover,将异常和控制流程区分开。即通过panic抛出异常,然后在defer中,通过recover捕获这个异常,最后处理。

但是更加推荐的错误处理方法:
Golang中我们通常会在函数或方法中返回error结构对象来判断是否有异常出现,并且可以更具需要自定义各种类型的error。如果返回的 error 值为 nil,则表示未遇到错误,否则 error 会返回一个字符串,用于说明遇到了什么错误。

type error interface {    Error() string}golang 中内置的错误类型 error 是一个接口类型,自定义的错误类型必须实现 Error()方法

如何生成error?

方式一:New方法 原生
将字符串 text 包装成一个 error 对象返回

func New(text string) error {    return &errorString{text}}//例如var ErrShortWrite = errors.New("short write")

方式二:定义自己的错误

package mainimport (    "fmt"    "time")// MyError is an error implementation that includes a time and message.type MyError struct {    When time.Time    What string}func (e MyError) Error() string {    return fmt.Sprintf("%v: %v", e.When, e.What)}func oops() error {    return MyError{        time.Date(1989, 3, 15, 22, 30, 0, 0, time.UTC),        "the file system has gone away",    }}func main() {    if err := oops(); err != nil {        fmt.Println(err)    }}

defer:

defer是Go语言中的延迟执行语句,用来添加函数结束时执行的代码,常用于释放某些已分配的资源、关闭数据库连接、断开socket连接、解锁一个加锁的资源。

(1)defer执行顺序:

return xxx:赋值指令 + CALL defer指令 + RET指令return xxx会被改写成:返回值 = xxx调用defer函数空的return

整个return过程,没有defer之前,先在栈中写一个值,这个值会被当作返回值,然后再调用RET指令返回。return xxx语句汇编后是 1.先给返回值赋值,2.再做一个空的return,( 赋值指令 + RET指令)。defer的执行是被插入到return指令之前的,有了defer之后,就变成了(赋值指令 + CALL defer指令 + RET指令)。
而在CALL defer函数中,有可能将最终的返回值改写了…也有可能没改写。总之,return xxx不是一条原子指令,如果返回值改写了,那么看上去就像defer是在return xxx之后执行的~

example1

func f() (result int) {    defer func() {        result++    }()    return 0}返回值:1

example2

func f() (r int) {     t := 5     defer func() {       t = t + 5     }()     return t}返回值:5

example3

func f() (r int) {    defer func(r int) {          r = r + 5    }(r)    return 1}返回值:1

example4

func f() (r int) {    return 1    defer func() {        r++        r++    }()    return 2}返回值:1注意:如果去掉了return 2,会出现语法错误:Missing return at the end of function 

example5

func main() {    for i:=0 ;i<5; i++ {       defer func() {           fmt.Println(i)       }()    }    fmt.Println("test:")}输出:test:55555func main() {    for i:=0 ;i<5; i++ {       defer func(i int) {           fmt.Println(i)       }(i)    }    fmt.Println("test:")}输出:test:43210

(2)defer栈

如果一个函数中有多个defer语句,它们会以LIFO(后进先出)的顺序执行。哪怕函数或某个延迟调用发生错误,这些调用依旧会被执。
package main //必须import "fmt"func test(x int) {    result := 100 / x    fmt.Println("result = ", result)    defer fmt.Println("three")}func main() {    defer fmt.Println("one")    defer fmt.Println("two")    //调用一个函数,导致内存出问题,除数不能为0    defer test(0)    defer fmt.Println("four")}注:defer 需要放在 panic 之前定义,因为由panic引发异常以后,程序停止执行,即不再执行下面代码,放在后面调用不了defer

输出结果:
image.png


panic:

当程序遇到致命错误导致无法继续运行时就会触发panic,例如:数据越界,空指针等。我们可以通过主动调用 panic() 函数,抛出致命的错误。
通过使用recover()函数,我可以捕获上述的错误异常

golang 的错误处理流程:当一个函数在执行过程中出现了异常或遇到
panic(),正常语句就会立即终止,然后执行 defer 语句,再报告异
常信息,最后退出 goroutine。如果在 defer 中使用了 recover()
函数,则会捕获错误信息,使该错误信息终止报告。

panic会在调用它的函数中向本层和它的所有上层逐级抛出,若一直没有recover将其捕获,程序退出后会产生crash。

例如:

package main //必须import "fmt"func test(x int) {    defer func() {        if err:=recover(); err!=nil{            fmt.Println(err)        }    }()    result := 100 / x    fmt.Println("result = ", result)}func main() {    //调用一个函数,导致内存出问题,除数不能为0     test(0)    defer fmt.Println("end")}输出:runtime error: integer divide by zeroend

注意:
1.defer要定义在panic之前
2.recover()的调用仅当它在defer函数被直接调用时才有效。在正常的执行过程中,调用 recover 会返回 nil 并且没有其他任何效果.
参考:http://www.coder55.com/articl…


文章来源:智云一二三科技

文章标题:【go】异常处理

文章地址:https://www.zhihuclub.com/429.shtml

关于作者: 智云科技

热门文章

网站地图