最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

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

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

根據(jù)代碼實(shí)例運(yùn)行結(jié)果來(lái)總結(jié)

說(shuō)明:定義一個(gè)函數(shù),有多個(gè)defer (用于判斷多個(gè)defer執(zhí)行順序),有panic和 return (判斷與defer對(duì)比執(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 捕獲到錯(cuò)誤:",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í)行結(jié)果:

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

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

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

執(zhí)行結(jié)果:

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

  • 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 捕獲到錯(cuò)誤:",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í)行結(jié)果:

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

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

  • 函數(shù)返回參數(shù)是匿名的 defer無(wú)法修改
  • 函數(shù)中有panic 匿名的返回值是零值,因?yàn)閞eturn賦值得不到執(zhí)行,defer又修改不到返回值

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

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

四、總結(jié):

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

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

一、panic()和recover()

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

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

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

簡(jiǎn)單來(lái)講:go中可以?huà)伋鲆粋€(gè)panic的異常,然后在defer中通過(guò)recover捕獲這個(gè)異常,然后正常處理。

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

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

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

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

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

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

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

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

代碼演示:

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

 運(yùn)行結(jié)果:

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

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

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

相關(guān)文章

  • 使用golang在windows上設(shè)置全局快捷鍵的操作

    使用golang在windows上設(shè)置全局快捷鍵的操作

    最近在工作中,總是重復(fù)的做事,想著自己設(shè)置一個(gè)快捷鍵實(shí)現(xiàn)windows 剪貼板的功能,所以本文小編給大家分享了使用golang在windows上設(shè)置全局快捷鍵的操作,文中有相關(guān)的代碼示例供大家參考,需要的朋友可以參考下
    2024-02-02
  • Go中的交叉編譯問(wèn)題

    Go中的交叉編譯問(wèn)題

    這篇文章主要介紹了Go中的交叉編譯問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-11-11
  • Go語(yǔ)言設(shè)計(jì)實(shí)現(xiàn)在任務(wù)欄里提醒你喝水的兔子

    Go語(yǔ)言設(shè)計(jì)實(shí)現(xiàn)在任務(wù)欄里提醒你喝水的兔子

    這篇文章主要為大家介紹了Go語(yǔ)言設(shè)計(jì)實(shí)現(xiàn)在任務(wù)欄里提醒你喝水的兔子示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-01-01
  • 詳解Go操作supervisor xml rpc接口及注意事項(xiàng)

    詳解Go操作supervisor xml rpc接口及注意事項(xiàng)

    這篇文章主要介紹了Go操作supervisor xml rpc接口及注意事項(xiàng),管理web,在配置文件中配置相關(guān)信息,通過(guò)go-supervisor的處理庫(kù)進(jìn)行操作,需要的朋友可以參考下
    2021-09-09
  • Go中的Context實(shí)現(xiàn)原理以及正確使用方式

    Go中的Context實(shí)現(xiàn)原理以及正確使用方式

    在 Go 語(yǔ)言中,Context 包是一種非常常用的工具,它被用來(lái)管理 goroutine 之間的通信和取消,本文將深入探討Context 包的基本原理,包括使用場(chǎng)景、原理和一些最佳實(shí)踐,感興趣的小伙伴跟著小編一起來(lái)看看吧
    2024-11-11
  • 一文告訴你大神是如何學(xué)習(xí)Go語(yǔ)言之make和new

    一文告訴你大神是如何學(xué)習(xí)Go語(yǔ)言之make和new

    當(dāng)我們想要在 Go 語(yǔ)言中初始化一個(gè)結(jié)構(gòu)時(shí),其實(shí)會(huì)使用到兩個(gè)完全不同的關(guān)鍵字,也就是 make 和 new,同時(shí)出現(xiàn)兩個(gè)用于『初始化』的關(guān)鍵字對(duì)于初學(xué)者來(lái)說(shuō)可能會(huì)感到非常困惑,不過(guò)它們兩者有著卻完全不同的作用,本文就和大家詳細(xì)講講
    2023-02-02
  • Golang字符串常用函數(shù)的使用

    Golang字符串常用函數(shù)的使用

    Golang提供了許多內(nèi)置的字符串函數(shù),這些函數(shù)可在處理字符串?dāng)?shù)據(jù)時(shí)幫助執(zhí)行一些操作,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-12-12
  • GO語(yǔ)言原生實(shí)現(xiàn)文件上傳功能

    GO語(yǔ)言原生實(shí)現(xiàn)文件上傳功能

    這篇文章主要為大家詳細(xì)介紹了GO語(yǔ)言原生實(shí)現(xiàn)文件上傳功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-07-07
  • Go構(gòu)建器模式構(gòu)建復(fù)雜對(duì)象方法實(shí)例

    Go構(gòu)建器模式構(gòu)建復(fù)雜對(duì)象方法實(shí)例

    本文介紹了構(gòu)建器模式,如何通過(guò)構(gòu)建器對(duì)象構(gòu)建復(fù)雜業(yè)務(wù)對(duì)象的方法實(shí)例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-12-12
  • Golang中crypto/cipher加密標(biāo)準(zhǔn)庫(kù)全面指南

    Golang中crypto/cipher加密標(biāo)準(zhǔn)庫(kù)全面指南

    本文主要介紹了Golang中crypto/cipher加密標(biāo)準(zhǔn)庫(kù),包括對(duì)稱(chēng)加密、非對(duì)稱(chēng)加密以及使用流加密和塊加密算法,文中通過(guò)示例代碼介紹的非常詳細(xì),需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2024-02-02

最新評(píng)論

辉县市| 雷山县| 定远县| 柳林县| 常德市| 石景山区| 大悟县| 道孚县| 达州市| 峡江县| 富阳市| 阿拉善左旗| 彭泽县| 鲁甸县| 定兴县| 龙门县| 新龙县| 鞍山市| 浦东新区| 高清| 贵南县| 鹤峰县| 晋江市| 芮城县| 内丘县| 乌兰县| 天柱县| 南昌市| 台南市| 宽城| 博白县| 通化县| 四川省| 尉犁县| 仙桃市| 乡城县| 蒲城县| 伊春市| 东丰县| 新民市| 印江|