go基础第四篇:error、panic、recover

error

error是go自带的一个接口,只有一个Error()方法,没有入参,有一个string类型的出参。

go自带了很多实现了error接口的struct,如errorString、TimeoutError、DNSError等。

errorString只有一个string型的属性,我们可以通过errors包的New(text string)函数获取指向errorString实例的指针。示例如下:

func Check(i int) (int, error) {
    if i < 0 {
        return -1, errors.New("negative")
    } else {
        return 1, nil
    }
}

func main() {
    i, err := Check(-1)
    if err != nil {
        fmt.Println("something wrong")
    } else {
        fmt.Println("going on,i=", i)
    }
}

error实例能否用==比较?

github.com/pkg/errors是一个比较好用的error相关的包。

panic

panic是个函数,有一个空接口类型的入参(可传任意类型,如字符串、error等等),无出参,作用类似于java中的throw new RuntimeException(msg),panic之后的代码不执行,程序会非零退出。

func main() {
    fmt.Println(1)
    panic("something wrong")
    fmt.Println(2)
}

只会打印1,不会打印2,main函数非零退出。

recover

recover也是个函数,没有入参,出参是个空接口类型,具体返回什么类型取决于使用的场景:

如果recover()在defer后面的函数中调用,则如果goroutine panic了,则recover()函数返回panic函数的入参,同时panic会被压制住,程序不会非零退出了,否则返回nil。如果不是在defer后面的函数中调用,则返回nil,且不会压制panic。

recover()函数不包装进一个函数中调用,而是直接在defer后面调用的话,没有任何效果。

recover()函数作用有点像java中的catch,因为它在一些情况下可以压制panic。但不是完全一样。因为recover()函数在类似finally块中执行才有意义,而catch没有在finally块中。

示例如下:

func MayPanic(i int) int {
    if i == 0 {
        panic("不能为0")
    } else if i < 0 {
        panic(errors.New("不能小于0"))
    }
    return 1
}

func main() {
    defer func() {
        if r := recover(); r != nil {
            fmt.Println(r)
            fmt.Println(reflect.TypeOf(r))
        }
    }()
    //i := MayPanic(0)
    i := MayPanic(-1)
    fmt.Println(i)
}

上例中,recover()在defer后面的函数中调用,且协程执行panic(errors.New("不能小于0"))而panic了,所以recover()函数返回error。main函数不会非零退出。

func main() {
    func() {
        if r := recover(); r == nil {
            fmt.Println(r)
            fmt.Println(reflect.TypeOf(r))
        }
    }()
    i := MayPanic(1)
    fmt.Println(i)
}

上例中,recover()函数虽然在defer后面的函数中调用,但是协程没有panic,所以recover()函数返回nil。

func MayPanic(i int) int {
    if i == 0 {
        panic("不能为0")
    } else if i < 0 {
        panic(errors.New("不能小于0"))
    }
    return 1
}

func main() {
    func() {
        if r := recover(); r == nil {
            fmt.Println(r)
            fmt.Println(reflect.TypeOf(r))
        }
    }()
    i := MayPanic(-1)
    fmt.Println(i)
}

上例中,recover()不是在defer后面的函数中调用的,所以返回值是nil。

原文地址:https://www.cnblogs.com/koushr/p/13371290.html