Hi,大家好,我是明哥,
在自己學習 Golang 的這段時間里,我寫了詳細的學習筆記放在我的個人微信公眾號 《Go編程時光》,對于 Go 語言,我也算是個初學者,因此寫的東西應該會比較適合剛接觸的同學,如果你也是剛學習 Go 語言,不防關注一下,一起學習,一起成長,
我的在線博客:http://golang.iswbm.com
我的 Github:github.com/iswbm/GolangCodingTime
編程語言一般都會有例外捕獲機制,在 Python 中 是使用raise 和 try-except 陳述句來實作的例外拋出和例外捕獲的,
在 Golang 中,有不少常規錯誤,在編譯階段就能提前告警,比如語法錯誤或型別錯誤等,但是有些錯誤僅能在程式運行后才能發生,比如陣列訪問越界、空指標參考等,這些運行時錯誤會引起程式退出,
當然能觸發程式宕機退出的,也可以是我們自己,比如經過檢查判斷,當前環境無法達到我們程式進行的預期條件時(比如一個服務指定監聽埠被其他程式占用),可以手動觸發 panic,讓程式退出停止運行,
1. 觸發panic
手動觸發宕機,是非常簡單的一件事,只需要呼叫 panic 這個內置函式即可,就像這樣子
package main
func main() {
panic("crash")
}
運行后,直接報錯宕機
$ go run main.go
go run main.go
panic: crash
goroutine 1 [running]:
main.main()
E:/Go-Code/main.go:4 +0x40
exit status 2
2. 捕獲 panic
發生了例外,有時候就得捕獲,就像 Python 中的 except 一樣,那 Golang 中是如何做到的呢?
這就不得不引出另外一個內建函式 -- recover,它可以讓程式在發生宕機后起生回生,
但是 recover 的使用,有一個條件,就是它必須在 defer 函式中才能生效,其他作用域下,它是不作業的,
這是一個簡單的例子
import "fmt"
func set_data(x int) {
defer func() {
// recover() 可以將捕獲到的panic資訊列印
if err := recover(); err != nil {
fmt.Println(err)
}
}()
// 故意制造陣列越界,觸發 panic
var arr [10]int
arr[x] = 88
}
func main() {
set_data(20)
// 如果能執行到這句,說明panic被捕獲了
// 后續的程式能繼續運行
fmt.Println("everything is ok")
}
運行后,輸出如下
$ go run main.go
runtime error: index out of range [20] with length 10
everything is ok
通常來說,不應該對進入 panic 宕機的程式做任何處理,但有時,需要我們可以從宕機中恢復,至少我們可以在程式崩潰前,做一些操作,舉個例子,當 web 服務器遇到不可預料的嚴重問題時,在崩潰前應該將所有的連接關閉,如果不做任何處理,會使得客戶端一直處于等待狀態,如果 web 服務器還在開發階段,服務器甚至可以將例外資訊反饋到客戶端,幫助除錯,
3. 無法跨協程
從上面的例子,可以看到,即使 panic 會導致整個程式退出,但在退出前,若有 defer 延遲函式,還是得執行完 defer ,
但是這個 defer 在多個協程之間是沒有效果,在子協程里觸發 panic,只能觸發自己協程內的 defer,而不能呼叫 main 協程里的 defer 函式的,
來做個實驗就知道了
import (
"fmt"
"time"
)
func main() {
// 這個 defer 并不會執行
defer fmt.Println("in main")
go func() {
defer println("in goroutine")
panic("")
}()
time.Sleep(2 * time.Second)
}
輸出如下
in goroutine
panic:
goroutine 6 [running]:
main.main.func1()
E:/Go-Code/main.go:12 +0x7b
created by main.main
E:/Go-Code/main.go:10 +0xbc
exit status 2
4. 總結一下
Golang 例外的拋出與捕獲,依賴兩個內置函式:
- panic:拋出例外,使程式崩潰
- recover:捕獲例外,恢復程式或做收尾作業
revocer 呼叫后,拋出的 panic 將會在此處終結,不會再外拋,但是 recover,并不能任意使用,它有強制要求,必須得在 defer 下才能發揮用途,
系列導讀
01. 開發環境的搭建(Goland & VS Code)
02. 學習五種變數創建的方法
03. 詳解資料型別:****整形與浮點型
04. 詳解資料型別:byte、rune與string
05. 詳解資料型別:陣列與切片
06. 詳解資料型別:字典與布爾型別
07. 詳解資料型別:指標
08. 面向物件編程:結構體與繼承
09. 一篇文章理解 Go 里的函式
10. Go語言流程控制:if-else 條件陳述句
11. Go語言流程控制:switch-case 選擇陳述句
12. Go語言流程控制:for 回圈陳述句
13. Go語言流程控制:goto 無條件跳轉
14. Go語言流程控制:defer 延遲呼叫
15. 面向物件編程:介面與多型
16. 關鍵字:make 和 new 的區別?
17. 一篇文章理解 Go 里的陳述句塊與作用域
18. 學習 Go 協程:goroutine
19. 學習 Go 協程:詳解信道/通道
20. 幾個信道死鎖經典錯誤案例詳解
21. 學習 Go 協程:WaitGroup
22. 學習 Go 協程:互斥鎖和讀寫鎖
23. Go 里的例外處理:panic 和 recover
24. 超詳細解讀 Go Modules 前世今生及入門使用
25. Go 語言中關于包匯入必學的 8 個知識點
26. 如何開源自己寫的模塊給別人用?
27. 說說 Go 語言中的型別斷言?
28. 這五點帶你理解Go語言的select用法

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/13833.html
標籤:Go
下一篇:1.hello,world
