網(wǎng)站首頁(yè) 編程語(yǔ)言 正文
先了解什么是defer
Go語(yǔ)言中的defer與return執(zhí)行的先后順序
Go語(yǔ)言的 defer 語(yǔ)句會(huì)將其后面跟隨的語(yǔ)句進(jìn)行延遲處理,在 defer 歸屬的函數(shù)即將返回時(shí),將延遲處理的語(yǔ)句按 defer 的逆序進(jìn)行執(zhí)行.也就是說(shuō),先被 defer 的語(yǔ)句最后被執(zhí)行,最后被 defer 的語(yǔ)句,最先被執(zhí)行。(與棧的先入后出是一個(gè)道理,也可以將其理解為入棧和出棧)
舉一個(gè)簡(jiǎn)單的例子
func main() { a, b := 111, 333 defer fmt.Println("b= ", b) fmt.Println("a= ", a) } 打印結(jié)果: a= 111 b= 333
可以看到雖然執(zhí)行語(yǔ)句時(shí)b在前,但是輸出結(jié)果為b在最后被輸出。
defer 的用法
(簡(jiǎn)單講解,細(xì)節(jié)請(qǐng)自行查閱資料)
一般用來(lái)釋放資源或者讀寫(xiě)操作,當(dāng)處理業(yè)務(wù)或邏輯中涉及成對(duì)的操作是一件比較煩瑣的事情,比如打開(kāi)和關(guān)閉文件、接收請(qǐng)求和回復(fù)請(qǐng)求、加鎖和解鎖等。在這些操作中,最容易忽略的就是在每個(gè)函數(shù)退出處正確地釋放和關(guān)閉資源。比如下面一個(gè)例子
func main(){ a := 1 out := bufio.NewWriter(os.Stdout) defer out.Flush() fmt.Fprintln(out, a) } 輸出結(jié)果: 1
就可以在最后將結(jié)果打印到控制臺(tái)中去,類(lèi)似的用法如關(guān)閉數(shù)據(jù)庫(kù)資源等等。如果這個(gè)例子太過(guò)于簡(jiǎn)單,那么來(lái)看下個(gè)例子。
var a bool = true defer func() { fmt.Println("1") }() if a == true { fmt.Println("2") return } defer func() { fmt.Println("3") }() 輸出結(jié)果: 2 1
我們會(huì)發(fā)現(xiàn)defer語(yǔ)句也是需要被執(zhí)行的,如果在defer函數(shù)執(zhí)行之前就執(zhí)行return。defer后的語(yǔ)句就不會(huì)再被執(zhí)行了。但是如果是在return之前defer已經(jīng)執(zhí)行,則defer中的語(yǔ)句將會(huì)在return執(zhí)行之前先一步進(jìn)行執(zhí)行.
那么defer 和 return有什么聯(lián)系?
defer 是延遲執(zhí)行語(yǔ)句,return是返回語(yǔ)句,那么肯定出現(xiàn)誰(shuí)先誰(shuí)后的問(wèn)題。下面看一個(gè)經(jīng)典的例子吧
func increaseA() int { var i int defer func() { i++ }() return i } func increaseB() (r int) { defer func() { r++ }() return r } func main() { fmt.Println(increaseA()) fmt.Println(increaseB()) } 輸出結(jié)果為: 0 1
肯定有人覺(jué)得有疑惑,為什么A函數(shù)沒(méi)有輸出,B函數(shù)卻輸出了呢?為什么答案不是1和0呢?
原因:
先說(shuō)結(jié)論:defer 修飾的匿名函數(shù),只能更新具名返回值.那么這會(huì)導(dǎo)致什么問(wèn)題呢?我們來(lái)逐步分析這個(gè)例子。
- 在increaseA()函數(shù)中有一個(gè)聲明i,表示i在該函數(shù)內(nèi)已經(jīng)被生成,是有名稱(chēng)的變量。但該函數(shù)返回參數(shù)為匿名參數(shù).
- 在increaseB()函數(shù)中沒(méi)有聲明r,是匿名變量。但該函數(shù)返回參數(shù)為具名參數(shù).
- func increaseA() int,返回值i=0的時(shí)候該值已經(jīng)被綁定到返回值里了,defer再去改i已經(jīng)沒(méi)用了.
- func increaseB() (r int), 返回值r先把返回變量設(shè)為0,defer又把r改為1.這時(shí)候還能生效. 因此答案很明顯為 1 和 0.
更進(jìn)一步理解
我們?nèi)粝胍M(jìn)一步理解也可以去輸出匯編語(yǔ)句,然后進(jìn)行研讀,可惜我是個(gè)菜鳥(niǎo)讀不懂匯編語(yǔ)言!但我們可以從return入手
我們要理解return 返回值的運(yùn)行機(jī)制:
return
并非原子操作,分為賦值,和返回值兩步操作.實(shí)際上return
執(zhí)行了兩步操作,因?yàn)榉祷刂禌](méi)有命名,所以return
默認(rèn)指定了一個(gè)返回值(假設(shè)為a),首先將i賦值給a,后續(xù)的操作因?yàn)槭轻槍?duì)i進(jìn)行的,所以不會(huì)影響a, 此后因?yàn)閍不會(huì)更新,所以return a
不會(huì)改變.
var i int a := i return a
但是如果return的參數(shù)a是具名參數(shù),就像上述例子中increaseB()函數(shù)一樣。a就相當(dāng)于命名的變量i, 因?yàn)樗械牟僮鞫际腔诿兞縤(a),返回值也是i, 所以每一次defer操作,都會(huì)更新返回值i.
省流小結(jié)
return會(huì)將返回值先保存起來(lái),對(duì)于無(wú)名返回值來(lái)說(shuō),保存在一個(gè)臨時(shí)對(duì)象中,defer是看不到這個(gè)臨時(shí)對(duì)象的;而對(duì)于有名返回值來(lái)說(shuō),就保存在已命名的變量中。
原文鏈接:https://juejin.cn/post/7171066100052918308
相關(guān)推薦
- 2023-01-01 C++日期和時(shí)間編程小結(jié)_C 語(yǔ)言
- 2022-10-27 C++設(shè)計(jì)模式中的工廠模式詳細(xì)介紹_C 語(yǔ)言
- 2021-12-16 Warning: Can‘t perform a React state update on an
- 2022-04-11 C#基于Sockets類(lèi)實(shí)現(xiàn)TCP通訊_C#教程
- 2022-06-15 C#實(shí)現(xiàn)希爾排序_C#教程
- 2024-03-22 【IDEA】成功解決導(dǎo)入配置文件處理器spring-boot-configuration-proce
- 2022-07-13 VMware Workstation Pro界面設(shè)置為中文界面
- 2022-07-07 C#操作注冊(cè)表之RegistryKey類(lèi)_C#教程
- 最近更新
-
- window11 系統(tǒng)安裝 yarn
- 超詳細(xì)win安裝深度學(xué)習(xí)環(huán)境2025年最新版(
- Linux 中運(yùn)行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲(chǔ)小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎(chǔ)操作-- 運(yùn)算符,流程控制 Flo
- 1. Int 和Integer 的區(qū)別,Jav
- spring @retryable不生效的一種
- Spring Security之認(rèn)證信息的處理
- Spring Security之認(rèn)證過(guò)濾器
- Spring Security概述快速入門(mén)
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權(quán)
- redisson分布式鎖中waittime的設(shè)
- maven:解決release錯(cuò)誤:Artif
- restTemplate使用總結(jié)
- Spring Security之安全異常處理
- MybatisPlus優(yōu)雅實(shí)現(xiàn)加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務(wù)發(fā)現(xiàn)-Nac
- Spring Security之基于HttpR
- Redis 底層數(shù)據(jù)結(jié)構(gòu)-簡(jiǎn)單動(dòng)態(tài)字符串(SD
- arthas操作spring被代理目標(biāo)對(duì)象命令
- Spring中的單例模式應(yīng)用詳解
- 聊聊消息隊(duì)列,發(fā)送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠(yuǎn)程分支