<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
Golang中當程式發生致命異常時(比如陣列下標越界,注意這裡的異常並不是error),Golang程式會panic(執行時恐慌)。當程式發生panic時,程式會執行當前棧中的defer 函數列表。然後列印引發panic的具體資訊,最後程序退出,本篇文章我們一起探討Golang中的panic以及如何利用defer 和 recover 來恢復這種致命的異常
分析造成panic堆疊資訊
func main() { f1() fmt.Println("main func end") } func f1() { fmt.Println("func f1 start") arr := []int{} fmt.Println(arr[10]) fmt.Println("func f1 end") }
上述程式碼中,我在main函數(主協程)中呼叫了f1函數,在呼叫完該函數後,我列印了「main func end」,程式如果正常執行的話會輸出
func f1 start
func f1 end
main func end
很明顯我們可以看出 f1 函數中,切片arr是沒有索引為10的元素的,這個時候程式執行時會造成panic,下面是程式panic時,console列印的堆疊資訊
func f1 start
panic: runtime error: index out of range [10] with length 0
goroutine 1 [running]:
main.f1()
/Users/carlos/go/src/test/demo01.go:15 +0x78
main.main()
/Users/carlos/go/src/test/demo01.go:8 +0x20
Process finished with the exit code 2
我們從堆疊中可以發現:
程式會在造成panic所處的位置終止
我們可以看到錯誤資訊中只輸出了 func f1 start
產生panic的原因
panic: runtime error: index out of range [10] with length 0
是哪裡造成的panic
goroutine 1 [running] // 執行該程式的協程
main.f1()
/Users/carlos/go/src/test/demo01.go:15 +0x78 // f1 函數,當前demo01檔案的低15行
main.main()
/Users/carlos/go/src/test/demo01.go:8 +0x20 // main 函數,當前檔案的弟8行
從上面的panic詳情我們可以看出,錯誤鏈是通過棧的形式展現出來的(mian函數先呼叫,然後在mian中呼叫f1),所以大家以後在程式發生panic時檢視堆疊資訊時可以先看最上層的錯誤,因為這裡是造成panic的根本原因
Golang中提供了recover函數用來恢復因panic造成的程式崩潰。recover函數有一個返回值來告訴我們panic產生的具體原因。下面我們通過程式碼來進行演示
func main() { f1() r := recover() fmt.Printf("%s n", r) fmt.Println("main func end") } func f1() { fmt.Println("func f1 start") arr := []int{} fmt.Println(arr[10]) fmt.Println("func f1 end") }
上述程式碼中我只是在呼叫f1函數的下一行呼叫了recover函數,這樣一來我們的理想狀態了能夠恢復程式,讓程式執行完main函數中剩下的程式碼(列印panic資訊,最後列印 main func end),當我們執行該程式的時候發現recover並沒有起到作用,這是因為當f1造成panic時,f1下方的recover函數根本沒有機會執行。
下面我將上述程式碼進行一個簡單的改造:
func main() { defer func() { fmt.Println("defer func start") if r := recover(); r != nil { fmt.Printf("%s n", r) } fmt.Println("defer func end") }() f1() fmt.Println("main func end") } func f1() { fmt.Println("func f1 start") arr := []int{} fmt.Println(arr[10]) fmt.Println("func f1 end") }
輸出
func f1 start
defer func start
runtime error: index out of range [10] with length 0
defer func end
上述程式碼中,我只是在main函數最開頭新增了一個defer 函數,並在該函數中呼叫了recover函數。注意,我們在文章的最開頭已經說明了,當程式發生panic時,程式會依次執行棧中的defer函數(關於defer函數請閱讀官網描述)。所以當前程式發生panic時在程序退出之前會走到defer函數中執行recover函數,recover函數會恢復當前程序並列印錯誤資訊。
這裡我需要特別提醒你一點,最好將defer語句寫在函數的最前面。如果上述例子我將f1的呼叫寫在defer函數之前,你會發現recover函數還是沒有執行
func main() { f1() defer func() { fmt.Println("defer func start") if r := recover(); r != nil { fmt.Printf("%s n", r) } fmt.Println("defer func end") }() fmt.Println("main func end") }
這是因為f1造成panic時,defer函數根本就沒有壓入函數呼叫棧中。
當你的專案中特別依賴一些元件時,比如一些web專案中經常會在程序啟動之前初始化一些mysql,mq控制程式碼。這些範例對業務來說是非常重要的,所以當這些範例初始化失敗時我們可以直接讓當前程式panic(手動panic),然後及時發現問題並解決。這樣總比你帶著問題上線後,然後一批流入打入進來,使用者端瘋狂報錯要好
Golang中手動呼叫panic:
func main() { initMysql() } func initMysql() { panic("init mysql failed") // panic可以接收一個interface型別的引數 }
到此這篇關於Golang中panic的例外處理的文章就介紹到這了,更多相關Golang panic內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45