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

Go語言defer的一些神奇規(guī)則示例詳解

 更新時(shí)間:2022年11月17日 16:15:42   作者:程序員麻辣燙  
這篇文章主要為大家介紹了Go語言defer的一些神奇規(guī)則示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

測(cè)試題

defer有一些規(guī)則,如果不了解,代碼實(shí)現(xiàn)的最終結(jié)果會(huì)與預(yù)期不一致。對(duì)于這些規(guī)則,你了解嗎?

這是關(guān)于defer使用的代碼,可以先考慮一下返回值。

package main
import (
	"fmt"
)
/**
 * @Author: Jason Pang
 * @Description: 快照
 */
func deferFuncParameter1() {
	var aInt = 1
	defer fmt.Println(aInt)
	aInt = 2
	return
}
/**
 * @Author: Jason Pang
 * @Description: 快照
 */
func deferFuncParameter2() {
	var aInt = 1
	defer func(t int) {
		fmt.Println(t)
	}(aInt)
	aInt = 2
	return
}
/**
 * @Author: Jason Pang
 * @Description: 動(dòng)態(tài)
 */
func deferFuncParameter3() {
	var aInt = 1
	defer func() {
		fmt.Println(aInt)
	}()
	aInt = 2
	return
}
/**
 * @Author: Jason Pang
 * @Description: 影響返回值
 * @return ret
 */
func deferFuncReturn1() (ret int) {
	ret = 10
	defer func() {
		ret++
		fmt.Println("-----", ret)
	}()
	return 2
}
/**
 * @Author: Jason Pang
 * @Description: 不影響返回值
 * @return ret
 */
func deferFuncReturn2() (ret int) {
	ret = 10
	defer func(ret int) {
		ret++
		fmt.Println("-----", ret)
	}(ret)
	return 2
}
/**
 * @Author: Jason Pang
 * @Description: defer順序
 */
func deferFuncSeq1() {
	var aInt = 1
	defer fmt.Println(aInt)
	aInt = 2
	defer fmt.Println(aInt)
	return
}
func main() {
	fmt.Println("快照")
	deferFuncParameter1()
	deferFuncParameter2()
	deferFuncParameter3()
	fmt.Println("返回值")
	fmt.Println(deferFuncReturn1())
	fmt.Println(deferFuncReturn2())
	fmt.Println("執(zhí)行順序")
	deferFuncSeq1()
}

正確輸出為:

? myproject go run main.go

快照

1

1

2

返回值

----- 3

3

----- 11

2

執(zhí)行順序

2

1

分析

defer有幾條重要規(guī)則,上面的結(jié)果都能從這些規(guī)則中找到答案。

規(guī)則一當(dāng)defer被聲明時(shí),其參數(shù)就會(huì)被實(shí)時(shí)解析

當(dāng)defer被聲明的時(shí)候,如果直接使用了參數(shù),此時(shí)的參數(shù)就會(huì)使用快照值,在整個(gè)生命周期內(nèi)不會(huì)變化。如deferFuncParameter1、deferFuncParameter2,雖然aInt在defer聲明后被變更,但defer里的值不會(huì)再變了。

func deferFuncParameter1() {
	var aInt = 1
	defer fmt.Println(aInt)
	aInt = 2
	return
}
func deferFuncParameter2() {
	var aInt = 1
	defer func(t int) {
		fmt.Println(t)
	}(aInt)
	aInt = 2
	return
}

與之相反的是deferFuncParameter3,隨aInt的變化而變化。

func deferFuncParameter3() {
	var aInt = 1
	defer func() {
		fmt.Println(aInt)
	}()
	aInt = 2
	return
}

規(guī)則二 defer可能操作主函數(shù)的具名返回值

defer有可能更改函數(shù)的返回值,這是最容易導(dǎo)致錯(cuò)誤的地方。

關(guān)鍵字_return_不是一個(gè)原子操作,實(shí)際上_return_只代理匯編指令_ret_,即將跳轉(zhuǎn)程序執(zhí)行。比如語句 return i ,實(shí)際上分兩步進(jìn)行,即將i值存入棧中作為返回值,然后執(zhí)行跳轉(zhuǎn),而defer的執(zhí)行時(shí)機(jī)正是跳轉(zhuǎn)前,所以說defer執(zhí)行時(shí)還是有機(jī)會(huì)操作返回值的。return i的執(zhí)行過程如下所示:

result = i 
執(zhí)行defer
return

所以基于這個(gè)規(guī)則,對(duì)于deferFuncReturn1,

func deferFuncReturn1() (ret int) {
	ret = 10
	defer func() {
		ret++
		fmt.Println("-----", ret)
	}()
	return 2
}

執(zhí)行過程為:

ret = 2
ret++
fmt.Println("-----", ret)
return

所以最終ret的值為3。

對(duì)于deferFuncReturn2,因?yàn)閐efer聲明的時(shí)候直接使用了參數(shù),所以使用的是快照,不會(huì)影響ret的返回值。

規(guī)則三 延遲函數(shù)執(zhí)行按后進(jìn)先出順序執(zhí)行

即先出現(xiàn)的 defer最后執(zhí)行

這個(gè)規(guī)則大家都很熟悉,defer按照棧的順序執(zhí)行。

坑實(shí)例

舉一個(gè)錯(cuò)誤使用defer的實(shí)例。在go中使用事務(wù)時(shí),有一種推薦寫法:將Rollback放到defer中,通過判斷函數(shù)是否有報(bào)錯(cuò)或者panic,來判斷是否要回滾。

func  Update() (resp *baseinfo.Resp, err error) {
	//開啟事務(wù)
	panicked := true
	tx, err := db.TXBegin()
	if err != nil {
		return resp, nil
	}
	defer func() {
		if panicked || err != nil {
			tx.Rollback()
		}
	}()
	//更新
	err = h.update(shopId, tx)
	if err != nil {//失敗返回
		return resp, nil
	}
	panicked = false
	err = tx.Commit().Error
	if err != nil { //失敗返回
		return resp, nil
	}
	return
}

判斷回滾的err正是函數(shù)的具名返回值,在有報(bào)錯(cuò)的情況下,返回值被賦值為nil,這意味如果有失敗,Rollback也不會(huì)被執(zhí)行。

之所以不將err直接返回,而是使用nil,是因?yàn)榭蚣茉O(shè)計(jì)的問題,業(yè)務(wù)錯(cuò)誤通過resp返回,如果直接返回err,框架會(huì)認(rèn)為是RPC錯(cuò)誤。

以上就是Go語言defer的一些神奇規(guī)則示例詳解的詳細(xì)內(nèi)容,更多關(guān)于Go語言defer規(guī)則的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 一文帶你了解Go語言中的類型斷言和類型轉(zhuǎn)換

    一文帶你了解Go語言中的類型斷言和類型轉(zhuǎn)換

    在Go中,類型斷言和類型轉(zhuǎn)換是一個(gè)令人困惑的事情,他們似乎都在做同樣的事情。最明顯的不同點(diǎn)是他們具有不同的語法(variable.(type)?vs?type(variable)?)。本文我們就來深入研究一下二者的區(qū)別
    2022-09-09
  • Go語言配置數(shù)據(jù)庫連接池的實(shí)現(xiàn)

    Go語言配置數(shù)據(jù)庫連接池的實(shí)現(xiàn)

    本文內(nèi)容我們將解釋連接池背后是如何工作的,并探索如何配置數(shù)據(jù)庫能改變或優(yōu)化其性能。文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-12-12
  • Golang?IOT中的數(shù)據(jù)序列化與解析過程

    Golang?IOT中的數(shù)據(jù)序列化與解析過程

    這篇文章主要介紹了Golang?IOT中的數(shù)據(jù)序列化與解析,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-05-05
  • Go實(shí)現(xiàn)短url項(xiàng)目的方法示例

    Go實(shí)現(xiàn)短url項(xiàng)目的方法示例

    這篇文章主要介紹了Go實(shí)現(xiàn)短url項(xiàng)目的方法示例,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2018-03-03
  • Go語言內(nèi)置包的使用

    Go語言內(nèi)置包的使用

    本文主要介紹了Go語言內(nèi)置包的使用,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-07-07
  • go語言基礎(chǔ)語法示例

    go語言基礎(chǔ)語法示例

    這篇文章主要介紹了go語言基礎(chǔ)語法示例,介紹了go語言較為全面的基礎(chǔ)知識(shí),具有一定參考價(jià)值,需要的可以了解下。
    2017-11-11
  • 一文秒懂Go 編寫命令行工具的代碼

    一文秒懂Go 編寫命令行工具的代碼

    這篇文章主要介紹了一文秒懂Go 編寫命令行工具的代碼,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-01-01
  • go并發(fā)利器sync.Once使用示例詳解

    go并發(fā)利器sync.Once使用示例詳解

    這篇文章主要為大家介紹了go并發(fā)利器sync.Once使用示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-03-03
  • goland 搭建 gin 框架的步驟詳解

    goland 搭建 gin 框架的步驟詳解

    這篇文章主要介紹了goland 搭建 gin 框架的相關(guān)知識(shí),本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-11-11
  • 一文詳解在Go中如何使用Viper來管理配置

    一文詳解在Go中如何使用Viper來管理配置

    Viper 是一個(gè)功能齊全的 Go 應(yīng)用程序配置庫,支持很多場景。在本文中,我們將深入探討 Viper 的各種用法和使用場景,以幫助讀者更好地了解和使用 Viper 來管理應(yīng)用程序配置,感興趣的同學(xué)可以參考閱讀
    2023-05-05

最新評(píng)論