網站首頁 編程語言 正文
延遲是什么
defer即延遲語句,極個別的情況下,Go才使?defer、panic、recover這種異常處理形式。
defer可以延遲函數、延遲?法、延遲參數。
延遲函數
可以在函數中添加多個defer語句。
當函數執?到最后時,這些defer語句會按照逆序執?,最后該函數返回。特別是當你在進??些打開資源的操作時,遇到錯誤需要提前返回,在返回前你需要關閉
相應的資源,不然很容易造成資源泄露等問題
如果有很多調?defer,那么defer是采?后進先出模式
在離開所在的?法時,執?(報錯的時候也會執?)
示例代碼1:
package main import "fmt" func main() { defer funA() funB() funC() fmt.Println("main...over....") } func funA() { fmt.Println("我是funA()...") } func funB() { // fmt.Println("我是funB()...") } func funC() { fmt.Println("我是funC()。。") }
運?結果:
我是funB()...
我是funC()。。
main...over....
我是funA()...
示例代碼2:
package main import "fmt" func main() { s1 := []int{78, 109, 2, 563, 300} largest(s1) } func finished() { fmt.Println("結束!") } func largest(s []int) { defer finished() fmt.Println("開始尋找最?數...") max := s[0] for _, v := range s { if v > max { max = v } } fmt.Printf("%v中的最?數為:%v \n", s , max) }
運?結果:
開始尋找最?數…
[78 109 2 563 300]中的最?數為:563
結束!
延遲?法
延遲并不僅僅局限于函數。延遲?個?法調?也是完全合法的。
示例代碼:
package main import "fmt" type person struct { firstName string lastName string } func (p person) fullName() { fmt.Printf("%s %s", p.firstName, p.lastName) } func main() { p := person{"Steven", "Wang"} defer p.fullName() fmt.Printf("Welcome ") }
運?結果:
Welcome Steven Wang
延遲參數
延遲函數的參數在執?延遲語句時被執?,?不是在執?實際的函數調?時執?。
示例代碼:
package main import "fmt" func printAdd(a , b int) { fmt.Printf("延遲函數中:參數a , b分別為%d,%d ,兩數之和為:%d\n", a , b , a+b) } func main() { a := 5 b := 6 //延遲函數的參數在執?延遲語句時被執?,?不是在執?實際的函數調 ?時執?。 defer printAdd(a , b) a = 10 b = 7 fmt.Printf("延遲函數執?前:參數a , b分別為%d,%d ,兩數之和為: %d\n", a , b , a+b) }
運?結果:
延遲函數執?前:參數a , b分別為10,7 ,兩數之和為:17
延遲函數中:參數a , b分別為5,6 ,兩數之和為:11
堆棧的推遲
當?個函數有多個延遲調?時,它們被添加到?個堆棧中,并在Last In First Out(LIFO)后進先出的順序中執?。
示例代碼:利?defer實現字符串倒序
package main import "fmt" func main() { name := "StevenWang歡迎學習區塊鏈" fmt.Printf("原始字符串: %s\n", name) fmt.Println("翻轉后字符串: ") ReverseString(name) } func ReverseString(str string) { for _, v := range []rune(str) { defer fmt.Printf("%c", v) } }
返回結果:
原始字符串: StevenWang歡迎學習區塊鏈
翻轉后字符串:
鏈塊區習學迎歡gnaWnevetS
延遲的應?
到?前為?,我們所寫的示例代碼,并沒有實際的應?。現在看?下關于延遲的應?。在不考慮代碼流的情況下,延遲被執?。讓我們以?個使?WaitGroup的程序示例來理解這個問題。我們將?先編寫程序?不使?延遲,然后我們將修改它以使?延遲,并理解延遲是多么有?。
示例代碼:
package main import ( "fmt" "sync" ) type rect struct { length int width int } func (r rect) area(wg *sync.WaitGroup) { if r.length < 0 { fmt.Printf("rect %v's length should be greater than zero\n", r) wg.Done() return } if r.width < 0 { fmt.Printf("rect %v's width should be greater than zero\n", r) wg.Done() return } area := r.length * r.width fmt.Printf("rect %v's area %d\n", r, area) wg.Done() } func main() { var wg sync.WaitGroup r1 := rect{-67, 89} r2 := rect{5, -67} r3 := rect{8, 9} rects := []rect{r1, r2, r3} for _, v := range rects { wg.Add(1) go v.area(&wg) } wg.Wait() fmt.Println("All go routines finished executing") }
修改以上代碼:
package main import ( "fmt" "sync" ) type rect struct { length int width int } func (r rect) area(wg *sync.WaitGroup) { defer wg.Done() if r.length < 0 { fmt.Printf("rect %v's length should be greater than zero\n", r) return } if r.width < 0 { fmt.Printf("rect %v's width should be greater than zero\n", r) return } area := r.length * r.width fmt.Printf("rect %v's area %d\n", r, area) } func main() { var wg sync.WaitGroup r1 := rect{-67, 89} r2 := rect{5, -67} r3 := rect{8, 9} rects := []rect{r1, r2, r3} for _, v := range rects { wg.Add(1) go v.area(&wg) } wg.Wait() fmt.Println("All go routines finished executing") }
程序運?結果:
rect {8 9}'s area 72
rect {-67 89}'s length should be greater than zero
rect {5 -67}'s width should be greater than zero
All go routines finished executing
panic和recover(宕機和宕機恢復)
panic和recover機制
1.概述:
panic:詞義"恐慌",recover:“恢復”
Go語?追求簡潔優雅,Go沒有像Java那樣的 try…catch…finally 異常處理機制。Go語?設計者認為,將異常與流程控制混在?起會讓代碼變得混亂。
Go語?中,使?多值返回來返回錯誤。不?異常代替錯誤,更不?異常來控制流程。
go語?利?panic(),recover(),實現程序中的極特殊的異常處理。換句話說,極個別的情況下,Go才使?defer、panic、recover這種異常處理形式。
- panic(),讓當前的程序進?恐慌,中斷程序的執?。或者說,panic是?個內建函數,可以中斷原有的控制流程,進??個令?恐慌的流程中。
- 當函數F調?panic,函數F的執?被中斷,但是F中的延遲函數會正常執?,然后F返回到調?它的地?。在調?的地?,F的?為就像調?了panic。這?過程繼續向上,直到發?panic的goroutine中所有調?的函數返回,此時程序退出。
- 恐慌可以直接調?panic產?。也可以由運?時錯誤產?,例如訪問越界的數組。
- recover 是?個內建的函數,可以讓進?令?恐慌的流程中的goroutine恢復過來。
- recover(),讓程序恢復,必須在defer函數中執?。換句話說,recover僅在延遲函數中有效。
- 在正常 的執?過程中,調?recover會返回nil,并且沒有其它任何效果。如果當前的goroutine陷?恐慌,調? recover可以捕獲到panic的輸?值,并且恢復正常的執?。
?定要記住,應當把它作為最后的?段來使?,也就是說,我們的代碼中應當沒有,或者很少有panic這樣的東?。
示例代碼
package main import "fmt" func main() { /* panic:詞義"恐慌", recover:"恢復" go語?利?panic(),recover(),實現程序中的極特殊的異常的處理 panic(),讓當前的程序進?恐慌,中斷程序的執? recover(),讓程序恢復,必須在defer函數中執? */ funA() funB() funC() fmt.Println("main...over....") } func funA() { fmt.Println("我是函數funA()...") } func funB() { //外圍函數 defer func() { if msg := recover(); msg != nil { fmt.Println(msg, "恢復啦。。。") } }() fmt.Println("我是函數funB()...") for i := 1; i <= 10; i++ { fmt.Println("i:", i) if i == 5 { //讓程序中斷 panic("funB函數,恐慌啦。。。") //打斷程序的執?。。 } } //當外圍函數中的代碼引發運?恐慌時,只有其中所有的延遲函數都執?完畢后,該運 ?時恐慌才會真正被擴展?調?函數。 } func funC() { defer func() { fmt.Println("func的延遲函數。。。") //if msg := recover(); msg != nil { // fmt.Println(msg, "恢復啦。。。") //} fmt.Println("recover執?了" , recover()) }() fmt.Println("我是函數funC()。。") panic("funC恐慌啦。。") }
原文鏈接:https://blog.csdn.net/ekcchina/article/details/125014828
相關推薦
- 2022-05-26 python中的getter與setter你了解嗎_python
- 2022-06-26 ASP.NET?Core中引用OpenAPI服務的添加示例_實用技巧
- 2023-10-13 獲取element-ui的Collapse折疊后高度
- 2022-12-11 Dos判斷文件夾是否存在,如果存在刪除,不存在創建_DOS/BAT
- 2023-03-27 淺談Rust?+=?運算符與?MIR?應用_Rust語言
- 2022-08-15 Spring框架常考知識點總結
- 2022-06-01 Android利用MediaRecorder實現錄音功能_Android
- 2022-04-06 教你用Python尋找重復文件并刪除的腳本寫法_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同步修改后的遠程分支