recover 問題解析

上個星期的文章說明了recover的一個問題,不過當(dāng)時給下的結(jié)論是因為defer的問題,今天特此再發(fā)一篇文章,算是勘誤了。
重新回顧下上回的問題:

func main()  {
    recoverMode4()
}

func recoverMode1()  {
    defer func() { // 有效的捕獲
        if r := recover();r != nil{
            fmt.Println(r)
        }
    }()

    panic("this is a panic!")
}




func recoverMode2()  {
    defer MyRecover() // 有效的捕獲

    panic("this is a panic!")
}

func recoverMode3()  {
    defer MyRecover() // 無效的捕獲

    go func() {
        panic("this is a panic!")
    }()
}



func recoverMode4()  {
    defer MyRecover2() // 無效的捕獲

    panic("this is a panic!")
}

func MyRecover()  {
    if r := recover();r != nil{
        fmt.Println(r)
    }
}
func MyRecover2()  {
     func() {
        if r := recover();r != nil{
            fmt.Println(r)
        }
    }()
}

上面的代碼分別展示了四中recover的類型,第一種是我們平常使用的,也是正常的方法,是能捕獲成功的;第二種其實和第一種沒有太大的區(qū)別,它的出現(xiàn)是為了引出第四種,和第四種相對應(yīng);第三種是不會捕獲成功的,這里展示了recover了第一個知識點:不能捕獲不在同一個groutine內(nèi)發(fā)生的panic;第四種和第二種方法相對應(yīng),但是他也無法捕獲成功,應(yīng)為其中的函數(shù)調(diào)用棧的原因。下面從recover的源碼角度分析,看看究竟:

func gorecover(argp uintptr) interface{} {
    // Must be in a function running as part of a deferred call during the panic.
    // Must be called from the topmost function of the call
    // (the function used in the defer statement).
    // p.argp is the argument pointer of that topmost deferred function call.
    // Compare against argp reported by caller.
    // If they match, the caller is the one who can recover.
    gp := getg()
    p := gp._panic
    if p != nil && !p.goexit && !p.recovered && argp == uintptr(p.argp) {
        p.recovered = true
        return p.arg
    }
    return nil

上面的就是recover的源碼,代碼很簡單,首先是getg,這個就是獲取獲取當(dāng)期那groutine,這也就解釋了上面的第三個判斷為啥沒辦法捕獲成功的原因,最后就是幾個簡單的判斷,不過這幾個簡單的判斷卻是學(xué)問很大的。前三個判斷都很好理解,分別判斷了是否產(chǎn)生panic,當(dāng)前函數(shù)是否已經(jīng)退出和是否已經(jīng)被修復(fù)。最后一個是當(dāng)前參數(shù)和當(dāng)前groutine的函數(shù)指針的判斷,這個判斷解釋了上面的第四個問題,其中參數(shù)p.argp是當(dāng)期最上層函數(shù)調(diào)用defer的函數(shù)指針,argp是調(diào)用recover的函數(shù)指針,在函數(shù)調(diào)用上,若是上面的第四種方法,p.argp指向的是MyRecover2函數(shù)內(nèi)的func,注意這里并不是MyRecover2,argp指向的是recoverMode4。這兩者不想等,無法recover成功。

recover 正確與錯誤的展示

如上圖所示,panic和recover之間必須隔著一層函數(shù)調(diào)用,沒有這層函數(shù)調(diào)用,或是大于一層的函數(shù)調(diào)用,recover都會失敗。

今天的課就到這里結(jié)束了,本節(jié)課分析了recover的失敗的兩個問題:
1、是不在同一個groutine的recover會失敗
2、recover和最上層的函數(shù)調(diào)用,中間必須隔著且僅僅是一層函數(shù)調(diào)用,不然也會失敗!

下課!

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容