網站首頁 編程語言 正文
一、運行時恐慌panic
panic是一種在運行時拋出來的異常。比如"index of range"。
panic的詳情:
package main import "fmt" func main() { oneC := []int{1, 2, 3, 4, 5} v5 := oneC[5] fmt.Println(v5) }
$ go run demo01.go
panic: runtime error: index out of range [5] with length 5
goroutine 1 [running]:
main.main()
?? ?/Users/lifei/Documents/workspace/githubRepositoies/gowp/projects/go-core-example/src/article19/q1/demo01.go:7 +0x1b
exit status 2
$
打印信息的第一行,"panic: "右邊的內容,正是panic包含的runtime.Error
類型值的字符串表示形式;
“goroutine 1 [running]” 表示有一個id為 1 的 goroutine在此panic被引發的時候正在運行;
這里的ID編號并不重要,是GO語言運行時系統內部給予的一個goroutine編號,我們在程序中無法獲取,也無法改變。
再下面是指出哪一行發生錯誤。“+0x1b”代表 此行代碼相對于其所屬函數的入口程序計數偏移量, 一般用途不大。
最后的 “exit status 2”,表明我的這個程序是以退出狀態碼2結束運行的。
在大多操作系統中,只要退出狀態碼不是0,都意味著程序運行的非正常結束。
二、panic被引發到程序終止經歷的過程
某個函數無疑觸發了panic:
- 初始的panic詳情會被建立起來,此行代碼所屬函數的執行隨機終止。
- 控制權立刻轉移到上一級;
- 控制權如此一層層沿著調用棧的反方向傳播至頂端,也就是我們編寫的最外層函數;
- 最終,控制權被GO語言運行時系統收回。隨后程序崩潰并終止運行;
panic 詳情會在控制權傳播的過程中,被逐漸地積累和完善,并且,控制權會一級一級地沿著調用棧的反方向傳播至頂端。因此,在針對某個 goroutine 的代碼執行信息中,調用棧底端的信息會先出現,然后是上一級調用的信息,以此類推,最后才是此調用棧頂端的信息。
三、有意引發一個panic并讓panic包含一個值
- 可以使用panic函數有意地引發一個 panic。
- 在調用panic函數時,把某個值作為參數傳給該函數就可以了。由于panic函數的唯一一個參數是空接口(也就是interface{})類型的,所以從語法上講,它可以接受任何類型的值。
- 但是,我們最好傳入error類型的錯誤值,或者其他的可以被有效序列化的值。這里的“有效序列化”指的是,可以更易讀地去表示形式轉換。
打印錯誤信息:
- 對于fmt包下的各種打印函數來說,error類型值的Error方法與其他類型值的String方法是等價的,它們的唯一結果都是string類型的;
- 如果某個值有可能會被記到日志里,那么就應該為它關聯String方法。
四、施加應對panic的保護措施從而避免程序崩潰
聯用defer語句和recover函數調用,才能夠恢復一個已經發生的 panic。
GO語言的內建函數recover專門用于恢復panic。recover函數無需任何參數,并且會返回一個空接口類型的值。
defer 語句用來延遲執行代碼。延遲到該語句所在的函數即將執行結束的那一刻,無論結束執行的原因是什么。
限制:有一些調用表達式是不能出現在這里的,包括:針對 Go 語言內建函數的調用表達式,以及針對unsafe包中的函數的調用表達式。
package main import ( "errors" "fmt" ) func main() { fmt.Println("Enter function main") // 延遲func函數的執行,直到main結束 defer func() { fmt.Println("Enter defer function") if p := recover(); p != nil { fmt.Printf("%v\n", p) } fmt.Println("Exit defer function") }() // 引發painc panic(errors.New("soming wrong")) fmt.Println("Exit function main") }
五、多條defer語句多條defer語句的執行順序
在同一個函數中,defer函數調用的執行順序與它們分別所屬的defer語句的出現順序(更嚴謹地說,是執行順序)完全相反。
當一個函數即將結束執行時,其中的寫在最下邊的defer函數調用會最先執行,其次是寫在它上邊、與它的距離最近的那個defer函數調用,以此類推,最上邊的defer函數調用會最后一個執行。
defer語句執行的內幕:
在defer語句每次執行的時候,Go 語言會把它攜帶的defer函數及其參數值另行存儲到一個鏈表中。
這個鏈表與該defer語句所屬的函數是對應的,并且,它是先進后出(FILO)的,相當于一個棧。
在需要執行某個函數中的defer函數調用的時候,Go 語言會先拿到對應的鏈表,然后從該鏈表中一個一個地取出defer函數及其參數值,并逐個執行調用。
package main import "fmt" func main() { defer fmt.Println("first defer") for i := 0; i < 3; i++ { defer fmt.Printf("defer in for %d\n", i) } defer fmt.Println("last defer") }
原文鏈接:https://blog.csdn.net/hefrankeleyn/article/details/128556143
相關推薦
- 2022-12-07 R語言隨機抽樣詳解_R語言
- 2022-11-06 關于useEffect的第二個參數解讀_React
- 2023-02-02 大型項目里Flutter測試應用實例集成測試深度使用詳解_Android
- 2023-07-09 【elementplus】body設置zoom后,el-table開啟show-overflow-t
- 2022-05-04 R語言邏輯型運算的實現_R語言
- 2022-03-14 xampp配置ssl 端口443后,無法開啟服務。提示端口被占用
- 2022-07-25 python如何將自己的包上傳到PyPi并可通過pip安裝的方法步驟_python
- 2022-10-06 Python?PaddlePaddle機器學習之求解線性模型_python
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支