欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

go?defer?return?panic?執(zhí)行順序示例詳解

 更新時間:2023年01月10日 14:24:50   作者:leo_jk  
這篇文章主要介紹了go?defer?return?panic?執(zhí)行順序,本文通過示例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下

根據(jù)代碼實例運行結果來總結

說明:定義一個函數(shù),有多個defer (用于判斷多個defer執(zhí)行順序),有panic和 return (判斷與defer對比執(zhí)行順序)

一、函數(shù)中有panic

package main
 
import "fmt"
 
func main() {
    fmt.Println("main func start")
    defer func(){
        fmt.Println("main defer func 1")
    }()
    s := test()
    fmt.Println("main get test() return:",s)
 
}
 
func test() (str string) {
    defer func() {
        //捕獲panic
        if msg := recover(); msg != nil {
            fmt.Println("test defer func1 捕獲到錯誤:",msg)
        }
        str = "bbb"
    }()
 
    defer func(){
        fmt.Println("test defer func2")
    }()
 
    defer func(){
        fmt.Println("test defer func3")
    }()
 
    str = "aaa"
    
    fmt.Println("panic拋出前")
    panic("test painc")
    fmt.Println("panic拋出后")
    
    return str
}

執(zhí)行結果:

根據(jù)執(zhí)行結果可知道:

  • 函數(shù)內(nèi)多個defer執(zhí)行順序是 先入后出(即入棧)
  • panic 先于defer執(zhí)行,不然defer函數(shù)內(nèi)捕獲不到錯誤
  • panic執(zhí)行后 后續(xù)邏輯及return 沒有執(zhí)行

二、然后將代碼中 panic注釋掉再執(zhí)行

執(zhí)行結果:

根據(jù)執(zhí)行結果可知:

  • defer中可以修改返回值,注意:前提是函數(shù)的返回值不是匿名的

三、函數(shù)返回的是匿名參數(shù)

package main
 
import "fmt"
 
func main() {
    fmt.Println("main func start")
    defer func(){
        fmt.Println("main defer func 1")
    }()
    s := test()
    fmt.Println("main get test() return:",s)
 
}
 
func test() (string) {
    str := "aaa"
    defer func() {
        //捕獲panic
        if msg := recover(); msg != nil {
            fmt.Println("test defer func1 捕獲到錯誤:",msg)
        }
        str = "ccc"
    }()
 
    defer func(){
        fmt.Println("test defer func2")
    }()
 
    defer func(){
        fmt.Println("test defer func3")
    }()
 
    fmt.Println("panic拋出前")
    panic("test painc")
    fmt.Println("panic拋出后")
 
    return str
}

執(zhí)行結果:

然后注釋掉panic執(zhí)行結果

根據(jù)執(zhí)行結果:

  • 函數(shù)返回參數(shù)是匿名的 defer無法修改
  • 函數(shù)中有panic 匿名的返回值是零值,因為return賦值得不到執(zhí)行,defer又修改不到返回值

***注意(非常重要):這里需要提到的是函數(shù)的return是分為兩個步驟:return最先執(zhí)行,先將結果寫入返回值中(即賦值);接著defer開始執(zhí)行一些收尾工作;最后函數(shù)攜帶當前返回值退出(即返回值)。

有panic的時候,return第一步?jīng)]有執(zhí)行到,無法將結果寫入返回值中,那么函數(shù)退出前則只能返回參數(shù)類型的零值

四、總結:

  1. 函數(shù)中有多個defer,則是按先進后出(壓棧)執(zhí)行
  2. panic先于defer執(zhí)行,所以能通過defer中去捕獲panic錯誤
  3. defer可以修改函數(shù)的返回參數(shù),前提是函數(shù)返回的參數(shù)不是匿名的
  4. 函數(shù)執(zhí)行出現(xiàn)panic那么return得不到執(zhí)行,如果返回參數(shù)是匿名的,那么函數(shù)最終返回的是返回參數(shù)的類型零值,如果返回參數(shù)不是匿名的,在panic前有對返回參數(shù)賦值,那么就能返回這個值,如果defer有對其修改,那么返回值則是defer修改的。

ps:go語言錯誤和異常處理,panic、defer、recover的執(zhí)行順序

一、panic()和recover()

Golang中引入兩個內(nèi)置函數(shù)panic和recover來觸發(fā)和終止異常處理流程,同時引入關鍵字defer來延遲執(zhí)行defer后面的函數(shù)。 一直等到包含defer語句的函數(shù)執(zhí)行完畢時,延遲函數(shù)(defer后的函數(shù))才會被執(zhí)行,而不管包含defer語句的函數(shù)是通過return的正常結束,還是由于panic導致的異常結束。你可以在一個函數(shù)中執(zhí)行多條defer語句,它們的執(zhí)行順序與聲明順序相反。 當程序運行時,如果遇到引用空指針、下標越界或顯式調(diào)用panic函數(shù)等情況,則先觸發(fā)panic函數(shù)的執(zhí)行,然后調(diào)用延遲函數(shù)。調(diào)用者繼續(xù)傳遞panic,因此該過程一直在調(diào)用棧中重復發(fā)生:函數(shù)停止執(zhí)行,調(diào)用延遲執(zhí)行函數(shù)等。如果一路在延遲函數(shù)中沒有recover函數(shù)的調(diào)用,則會到達該協(xié)程的起點,該協(xié)程結束,然后終止其他所有協(xié)程,包括主協(xié)程(類似于C語言中的主線程,該協(xié)程ID為1)。

panic: 1、內(nèi)建函數(shù) 2、假如函數(shù)F中書寫了panic語句,會終止其后要執(zhí)行的代碼,在panic所在函數(shù)F內(nèi)如果存在要執(zhí)行的defer函數(shù)列表,按照defer的逆序執(zhí)行 3、返回函數(shù)F的調(diào)用者G,在G中,調(diào)用函數(shù)F語句之后的代碼不會執(zhí)行,假如函數(shù)G中存在要執(zhí)行的defer函數(shù)列表,按照defer的逆序執(zhí)行,這里的defer 有點類似 try-catch-finally 中的 finally 4、直到goroutine整個退出,并報告錯誤

recover: 1、內(nèi)建函數(shù) 2、用來控制一個goroutine的panicking行為,捕獲panic,從而影響應用的行為 3、一般的調(diào)用建議 a). 在defer函數(shù)中,通過recever來終止一個gojroutine的panicking過程,從而恢復正常代碼的執(zhí)行 b). 可以獲取通過panic傳遞的error

簡單來講:go中可以拋出一個panic的異常,然后在defer中通過recover捕獲這個異常,然后正常處理。

錯誤和異常從Golang機制上講,就是error和panic的區(qū)別。很多其他語言也一樣,比如C++/Java,沒有error但有errno,沒有panic但有throw。

Golang錯誤和異常是可以互相轉(zhuǎn)換的:

錯誤轉(zhuǎn)異常,比如程序邏輯上嘗試請求某個URL,最多嘗試三次,嘗試三次的過程中請求失敗是錯誤,嘗試完第三次還不成功的話,失敗就被提升為異常了。異常轉(zhuǎn)錯誤,比如panic觸發(fā)的異常被recover恢復后,將返回值中error類型的變量進行賦值,以便上層函數(shù)繼續(xù)走錯誤處理流程。

什么情況下用錯誤表達,什么情況下用異常表達,就得有一套規(guī)則,否則很容易出現(xiàn)一切皆錯誤或一切皆異常的情況。

以下給出異常處理的作用域(場景):

空指針引用下標越界除數(shù)為0不應該出現(xiàn)的分支,比如default輸入不應該引起函數(shù)錯誤

其他場景我們使用錯誤處理,這使得我們的函數(shù)接口很精煉。對于異常,我們可以選擇在一個合適的上游去recover,并打印堆棧信息,使得部署后的程序不會終止。

說明: Golang錯誤處理方式一直是很多人詬病的地方,有些人吐槽說一半的代碼都是"if err != nil { / 打印 && 錯誤處理 / }",嚴重影響正常的處理邏輯。當我們區(qū)分錯誤和異常,根據(jù)規(guī)則設計函數(shù),就會大大提高可讀性和可維護性。

代碼演示:

package main
 
import "fmt"
 
func main() {
	/*
	panic:詞義"恐慌",
	recover:"恢復"
	go語言利用panic(),recover(),實現(xiàn)程序中的極特殊的異常的處理
		panic(),讓當前的程序進入恐慌,中斷程序的執(zhí)行
		recover(),讓程序恢復,必須在defer函數(shù)中執(zhí)行
	 */
	defer func(){
		if msg := recover();msg != nil{
			fmt.Println(msg,"程序回復啦。。。")
		}
	}()
	funA()
	defer myprint("defer main:3.....")
	funB()
	defer myprint("defer main:4.....")
 
	fmt.Println("main..over。。。。")
 
}
func myprint(s string){
	fmt.Println(s)
}
 
func funA(){
	fmt.Println("我是一個函數(shù)funA()....")
}
 
func funB(){//外圍函數(shù)
 
	fmt.Println("我是函數(shù)funB()...")
	defer myprint("defer funB():1.....")
 
	for i:= 1;i<=10;i++{
		fmt.Println("i:",i)
		if i == 5{
			//讓程序中斷
			panic("funB函數(shù),恐慌了")
		}
	}//當外圍函數(shù)的代碼中發(fā)生了運行恐慌,只有其中所有的已經(jīng)defer的函數(shù)全部都執(zhí)行完畢后,該運行恐慌才會真正被擴展至調(diào)用處。
	defer myprint("defer funB():2.....")
}

 運行結果:

我是一個函數(shù)funA()....
我是函數(shù)funB()...
i: 1
i: 2
i: 3
i: 4
i: 5
defer funB():1.....
defer main:3.....
funB函數(shù),恐慌了 程序回復啦。。。

可見當外圍函數(shù)的代碼中發(fā)生了運行恐慌,只有其中所有的已經(jīng)defer的函數(shù)全部都執(zhí)行完畢后,該運行恐慌才會真正被擴展至調(diào)用處。

到此這篇關于go defer return panic 執(zhí)行順序的文章就介紹到這了,更多相關go defer return panic 執(zhí)行順序內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • Go開發(fā)環(huán)境搭建詳細介紹

    Go開發(fā)環(huán)境搭建詳細介紹

    由于目前網(wǎng)上Go的開發(fā)環(huán)境搭建文章很多,有些比較老舊,都是基于 GOPATH的,給新入門的同學造成困擾。以下為2023 版 Go 開發(fā)環(huán)境搭建,可參照此教程搭建Go開發(fā)環(huán)境,有需要的朋友可以參考閱讀
    2023-04-04
  • Go語言題解LeetCode705設計哈希集合

    Go語言題解LeetCode705設計哈希集合

    這篇文章主要為大家介紹了Go語言題解LeetCode705設計哈希集合,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-12-12
  • golang雪花算法實現(xiàn)64位的ID的示例代碼

    golang雪花算法實現(xiàn)64位的ID的示例代碼

    本文展示了使用Go語言實現(xiàn)雪花算法生成64位ID的示例代碼,雪花算法通過當前時間戳、工作節(jié)點ID、數(shù)據(jù)中心ID和序列號生成唯一的64位ID,確保在分布式系統(tǒng)中的唯一性和時間順序性,感興趣的可以了解一下
    2024-09-09
  • Go語言中工作池的原理與實現(xiàn)

    Go語言中工作池的原理與實現(xiàn)

    工作池是一種并發(fā)編程模式,它使用一組固定數(shù)量的工作線程來執(zhí)行任務隊列中的工作單元,本文將介紹工作池的工作原理,并通過代碼示例演示其在實際應用中的用途,有需要的可以參考下
    2023-10-10
  • 淺談beego默認處理靜態(tài)文件性能低下的問題

    淺談beego默認處理靜態(tài)文件性能低下的問題

    下面小編就為大家?guī)硪黄獪\談beego默認處理靜態(tài)文件性能低下的問題。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-06-06
  • GO必知必會的常見面試題匯總

    GO必知必會的常見面試題匯總

    這篇文章主要為大家介紹了GO必知必會的常見面試題匯總
    2022-08-08
  • golang開發(fā)微框架Gin的安裝測試及簡介

    golang開發(fā)微框架Gin的安裝測試及簡介

    這篇文章主要為大家介紹了golang微框架Gin的安裝測試及簡介,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步早日升職加薪
    2021-11-11
  • golang為什么要統(tǒng)一錯誤處理

    golang為什么要統(tǒng)一錯誤處理

    這篇文章主要介紹了golang為什么要統(tǒng)一錯誤處理,統(tǒng)一錯誤處理的目的是為了前端開發(fā)接收到后端的statuscode,之后便于前端邏輯上開發(fā)以及開發(fā),下文具體操作過程需要的小伙伴可以參考一下
    2022-04-04
  • GoLand一鍵上傳項目到遠程服務器的方法步驟

    GoLand一鍵上傳項目到遠程服務器的方法步驟

    我們開發(fā)項目常常將項目上傳到linux遠程服務器上來運行,本文主要介紹了GoLand一鍵上傳項目到遠程服務器的方法步驟,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2022-06-06
  • golang下的GOPATH路徑問題及解決

    golang下的GOPATH路徑問題及解決

    為了方便,我一般使用task來管理項目的編譯等事項,由于才入門go,所以碰到一個問題,以此篇為記,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-01-01

最新評論