golang recover捕获不了

发布时间:2024-10-02 20:16:43

golang中recover无法捕获的情况

在golang中,使用recover函数可以在程序出现panic时进行异常恢复操作。然而,并不是所有的panic都可以被recover捕获到,有一些特定的情况下,recover是无法生效的。

未在goroutine中调用recover

当panic发生在一个goroutine中时,如果该goroutine没有通过defer调用recover函数进行异常恢复,那么该panic就无法被捕获到。

没有直接调用panic函数

如果panic是由其他函数调用触发的,而不是直接调用panic函数,那么在当前函数中通过recover是无法捕获到该panic的。例如:

func foo() {
    recover()
}

func bar() {
    defer foo()
    baz()
}

func baz() {
    panic("error")
}

func main() {
    bar()
}

在上述代码中,panic("error")的发生是由baz函数触发的,但是在foo函数中通过recover是无法捕获该panic的,因为panic是由baz函数直接调用的。

在延迟函数中直接调用panic

如果在延迟函数中直接调用panic函数,那么该panic是无法被recover捕获到的。例如:

func foo() {
    defer func() {
        if r := recover(); r != nil {
            fmt.Println("Recovered in foo", r)
        }
    }()
    
    panic("error")
}

func main() {
    foo()
}

在上述代码中,foo函数中的defer函数会尝试使用recover进行异常恢复,但是由于panic是直接在延迟函数中调用的,所以该panic无法被捕获到。

从不同goroutine中触发的panic

在多个goroutine并发执行的情况下,一个goroutine中的panic是无法被其他goroutine中的recover捕获到的。例如:

func foo() {
    go func() {
        panic("error")
    }()
    
    select {}
}

func main() {
    defer func() {
        if r := recover(); r != nil {
            fmt.Println("Recovered in main", r)
        }
    }()
    
    foo()
}

在上述代码中,foo函数中的panic是在一个新的goroutine中触发的,而main函数中的recover无法捕获到该panic。

由非当前goroutine触发的panic

如果一个goroutine中的panic是由另一个非该goroutine触发的,那么当前goroutine中通过recover是无法捕获到该panic的。例如:

func foo(c chan int) {
    select {
    case num := <-c:
        fmt.Println("Received", num)
    }
}

func main() {
    c := make(chan int)
    
    go func() {
        panic("error")
    }()
    
    defer func() {
        if r := recover(); r != nil {
            fmt.Println("Recovered in main", r)
        }
    }()
    
    foo(c)
}

在上述代码中,panic是在一个新的goroutine中触发的,而不是在main函数中。所以main函数中的recover是无法捕获到该panic的。

结论

尽管在golang中使用recover函数可以进行异常恢复操作,但是并不是所有的panic都能被recover捕获到。需要注意上述所提到的情况,在编写代码时要进行合理的异常处理,以避免未捕获的panic导致程序崩溃。

相关推荐