Go panic 用法

@TOC

<hr style=" border:solid; width:100px; height:1px;" color=#000000 size=1">

一拂盯、Go panic用法

Go語言追求簡潔優(yōu)雅坟桅,所以群扶,Go語言不支持傳統(tǒng)的 try…catch…finally 這種異常碗旅,因為Go語言的設(shè)計者們認為砚尽,將異常與控制結(jié)構(gòu)混在一起會很容易使得代碼變得混亂拆撼。因為開發(fā)者很容易濫用異常容劳,甚至一個小小的錯誤都拋出一個異常。在Go語言中闸度,使用多值返回來返回錯誤竭贩。不要用異常代替錯誤,更不要用來控制流程筋岛。在極個別的情況下娶视,也就是說,遇到真正的異常的情況下(比如除數(shù)為 0了)睁宰。才使用Go中引入的Exception處理:defer, panic, recover肪获。

這幾個異常的使用場景可以這么簡單描述:Go中可以拋出一個panic的異常,然后在defer中通過recover捕獲這個異常柒傻,然后正常處理孝赫。

package main

import "fmt"

func main(){
    fmt.Println("c")
     defer func(){ // 必須要先聲明defer,否則不能捕獲到panic異常
        fmt.Println("d")
        if err:=recover();err!=nil{
            fmt.Println(err) // 這里的err其實就是panic傳入的內(nèi)容红符,55
        }
        fmt.Println("e")
    }()

    f() //開始調(diào)用f
    fmt.Println("f") //這里開始下面代碼不會再執(zhí)行
}

func f(){
    fmt.Println("a")
    panic("異常信息")
    fmt.Println("b") //這里開始下面代碼不會再執(zhí)行
    fmt.Println("f")
}


輸出結(jié)果:

c
a
d
異常信息
e
  • 內(nèi)建函數(shù)
  • 假如函數(shù)F中書寫了panic語句青柄,會終止其后要執(zhí)行的代碼,在panic所在函數(shù)F內(nèi)如果存在要執(zhí)行的defer函數(shù)列表预侯,按照defer的逆序執(zhí)行
比如panic函數(shù)內(nèi)有:
    defer   函數(shù)1
    defer   函數(shù)2
    defer   函數(shù)3
那么執(zhí)行順序就是:
    函數(shù)3
    函數(shù)2
    函數(shù)1
  • 返回函數(shù)F的調(diào)用者G致开,在G中,調(diào)用函數(shù)F語句之后的代碼不會執(zhí)行萎馅,假如函數(shù)G中存在要執(zhí)行的defer函數(shù)列表双戳,按照defer的逆序執(zhí)行,這里的defer 有點類似 try-catch-finally 中的 finally
  • 到goroutine整個退出糜芳,并報告錯誤

二飒货、recover:

  • 內(nèi)建函數(shù)
  • 用來控制一個goroutine的panicking行為,捕獲panic峭竣,從而影響應(yīng)用的行為
  • 一般的調(diào)用建議(如上面的例子)
    a). 在defer函數(shù)中塘辅,通過recever來終止一個gojroutine的panicking過程,從而恢復(fù)正常代碼的執(zhí)行
    b). 可以獲取通過panic傳遞的error
    簡單來講:go中可以拋出一個panic的異常皆撩,然后在defer中通過recover捕獲這個異常扣墩,然后正常處理。

注意:利用recover處理panic指令,defer必須在panic之前聲明呻惕,否則當(dāng)panic時盘榨,recover無法捕獲到panic.

三、偶爾的 panic 是必要的

Go 是一種安全的語言蟆融,運行時檢查一些嚴重的編程錯誤草巡。例如在你訪問超出 slice 邊界的元素時,這種行為是未定義的型酥,因此 Go 會在運行時 panic山憨。例如下面的小程序。

package main

import (
    "fmt"
)

func main() {
    s := make([]string, 3)
    fmt.Println(s[5])
}

程序?qū)⒔K止于一個運行時 error弥喉。

panic: runtime error: index out of range

goroutine 1 [running]:
main.main()
    /tmp/sandbox209906601/main.go:9 +0x40

其他一些會引發(fā) panic 的就是通過值為 nil 的指針訪問結(jié)構(gòu)體的字段郁竟,關(guān)閉已經(jīng)關(guān)閉的 channel 等。怎樣選擇性的 panic 由境?可以通過訪問 slice 時返回 result棚亩,error 兩個值的方式實現(xiàn)。也可以將 slice 的元素賦值給一個可能返回 error 的函數(shù)虏杰,但是這樣會將代碼變復(fù)雜讥蟆。想象一下,寫一個小片段纺阔,foo瘸彤,bar,baz 都只是一個字符串的一個 slice笛钝,實現(xiàn)片段之間的拼接质况。

foo[i] = bar[i] + baz[i]

就會變成下面這樣冗長的代碼:

br, err := bar[i]
if err != nil {
    return err
}
bz, err := baz[i]
if err != nil {
    return err
}
err := assign_slice_element(foo, i, br + bz)
if err != nil {
    return err
 }

這不是開玩笑,不同語言處理這樣的方式是不一樣的玻靡。如果 slices/lists/arrays 的指針 i 越界了结榄,在 Python 和 Java 中就會拋出異常。C 中沒有越界檢查囤捻,所以你就可以盡情的蹂躪邊界外的內(nèi)存空間臼朗,最后將導(dǎo)致程序崩潰或者暴露安全漏洞。C++ 中將采用折中的處理方式最蕾。性能優(yōu)先的模塊采用這種不安全的 C 模式依溯,其他模塊(比如 std::vector::at)采用拋出異常的方式老厌。
因為上面重寫的小片段變得如此冗長是不可接受的瘟则。Go 選擇了 panic ,這是一種類似異常的機制枝秤,在代碼中保留了像 bugs 這樣最原始的異常條件醋拧。

這不只是內(nèi)建代碼能夠這樣用,自定義代碼也可以在任何需要的地方調(diào)用 panic。在有些可能導(dǎo)致可怕錯誤的地方還鼓勵使用 panic 拋出 error丹壕,比如 bug 或者一些關(guān)鍵因素被違反的時候庆械。比如在 swich 的某個 case 在當(dāng)前上下文中是不可能發(fā)生的,在這種 case 中只有一個 panic 函數(shù)菌赖。這無形中等價于 Python 中的 raise 或者 C++ 中的 throw缭乘。這也強有力的證明了在捕獲異常方面 Go 的異常處理的特殊之處。

Go 中 panic 恢復(fù)的限制條件

一般就HTTP服務(wù)的全局做一個recover,然后任何地方panic都能全局捕獲相應(yīng)一個錯誤

image.png
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末琉用,一起剝皮案震驚了整個濱河市堕绩,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌邑时,老刑警劉巖奴紧,帶你破解...
    沈念sama閱讀 206,968評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異晶丘,居然都是意外死亡黍氮,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評論 2 382
  • 文/潘曉璐 我一進店門浅浮,熙熙樓的掌柜王于貴愁眉苦臉地迎上來沫浆,“玉大人,你說我怎么就攤上這事滚秩〖祝” “怎么了?”我有些...
    開封第一講書人閱讀 153,220評論 0 344
  • 文/不壞的土叔 我叫張陵叔遂,是天一觀的道長他炊。 經(jīng)常有香客問我,道長已艰,這世上最難降的妖魔是什么痊末? 我笑而不...
    開封第一講書人閱讀 55,416評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮哩掺,結(jié)果婚禮上凿叠,老公的妹妹穿的比我還像新娘。我一直安慰自己嚼吞,他們只是感情好盒件,可當(dāng)我...
    茶點故事閱讀 64,425評論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著舱禽,像睡著了一般炒刁。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上誊稚,一...
    開封第一講書人閱讀 49,144評論 1 285
  • 那天翔始,我揣著相機與錄音罗心,去河邊找鬼。 笑死城瞎,一個胖子當(dāng)著我的面吹牛渤闷,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播脖镀,決...
    沈念sama閱讀 38,432評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼飒箭,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了蜒灰?” 一聲冷哼從身側(cè)響起补憾,我...
    開封第一講書人閱讀 37,088評論 0 261
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎卷员,沒想到半個月后盈匾,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,586評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡毕骡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,028評論 2 325
  • 正文 我和宋清朗相戀三年削饵,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片未巫。...
    茶點故事閱讀 38,137評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡窿撬,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出叙凡,到底是詐尸還是另有隱情劈伴,我是刑警寧澤,帶...
    沈念sama閱讀 33,783評論 4 324
  • 正文 年R本政府宣布握爷,位于F島的核電站跛璧,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏新啼。R本人自食惡果不足惜追城,卻給世界環(huán)境...
    茶點故事閱讀 39,343評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望燥撞。 院中可真熱鬧座柱,春花似錦、人聲如沸物舒。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,333評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽冠胯。三九已至火诸,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間涵叮,已是汗流浹背惭蹂。 一陣腳步聲響...
    開封第一講書人閱讀 31,559評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留割粮,地道東北人盾碗。 一個月前我還...
    沈念sama閱讀 45,595評論 2 355
  • 正文 我出身青樓,卻偏偏與公主長得像舀瓢,于是被迫代替她去往敵國和親廷雅。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,901評論 2 345

推薦閱讀更多精彩內(nèi)容