詳解golang?defer?閉包?匿名函數(shù)
defer用于資源的釋放,會(huì)在函數(shù)返回之前進(jìn)行調(diào)用。如果有多個(gè)defer表達(dá)式,調(diào)用順序類似于棧,越后面的defer表達(dá)式越先被調(diào)用。
defer的觸發(fā)時(shí)機(jī)
- 包裹著defer語句的函數(shù)返回時(shí)
- 包裹著defer語句的函數(shù)執(zhí)行到最后時(shí)
- 當(dāng)前goroutine發(fā)生Panic時(shí)
當(dāng)前goroutine發(fā)生Panic時(shí)
//輸出結(jié)果:return前執(zhí)行defer
func f1() {
defer fmt.Println("return前執(zhí)行defer")
return
}
//輸出結(jié)果:函數(shù)執(zhí)行
// 函數(shù)執(zhí)行到最后
func f2() {
defer fmt.Println("函數(shù)執(zhí)行到最后")
fmt.Println("函數(shù)執(zhí)行")
}
//輸出結(jié)果:panic前 第一個(gè)defer在Panic發(fā)生時(shí)執(zhí)行,第二個(gè)defer在Panic之后聲明,不能執(zhí)行到
func f3() {
defer fmt.Println("panic前")
panic("panic中")
defer fmt.Println("panic后")
}defer,return,返回值的執(zhí)行順序
- 先給返回值賦值
- 執(zhí)行defer語句
- 包裹函數(shù)return返回
func f1() int { //匿名返回值
var r int = 6
defer func() {
r *= 7
}()
return r
}
func f2() (r int) { //有名返回值
defer func() {
r *= 7
}()
return 6
}
func f3() (r int) { //有名返回值
defer func(r int) {
r *= 7
}(r)
return 6
}f1的執(zhí)行結(jié)果是6, f2的執(zhí)行結(jié)果是42,f3的執(zhí)行結(jié)果是6
最后看example3。它改寫后變成
func f1() (r int) {
r = 6 //給返回值賦值
func(r int) { //這里改的r是傳值傳進(jìn)去的r,不會(huì)改變要返回的那個(gè)r值
r *= 7
}(r)
return //空的return
}f1的結(jié)果是6。f1是匿名返回值,匿名返回值是在return執(zhí)行時(shí)被聲明,因此defer聲明時(shí),還不能訪問到匿名返回值,defer的修改不會(huì)影響到返回值。
f2先給返回值r賦值,r=6,執(zhí)行defer語句,defer修改r, r = 42,然后函數(shù)return。
f3是有名返回值,但是因?yàn)閞是作為defer的傳參,在聲明defer的時(shí)候,就進(jìn)行參數(shù)拷貝傳遞,所以defer只會(huì)對(duì)defer函數(shù)的局部參數(shù)有影響,不會(huì)影響到調(diào)用函數(shù)的返回值。
閉包與匿名函數(shù)
匿名函數(shù):沒有函數(shù)名的函數(shù)。函數(shù)也是一種類型,一個(gè)函數(shù)可以賦值給變量
閉包:可以使用另外一個(gè)函數(shù)作用域中的變量的函數(shù)。閉包復(fù)制的是原對(duì)象指針,這就很容易解釋延遲引用現(xiàn)象。
for i := 0; i <= 3; i++ {
defer func() {
fmt.Print(i)
}
}
//輸出結(jié)果時(shí) 3,3,3,3
因?yàn)閐efer函數(shù)的i是對(duì)for循環(huán)i的引用,defer延遲執(zhí)行,for循環(huán)到最后i是3,到defer執(zhí)行時(shí)i就是3
for i := 0; i <= 3; i++ {
defer func(i int) {
fmt.Print(i)
}(i)
}
//輸出結(jié)果時(shí) 3,2,1,0
因?yàn)閐efer函數(shù)的i是在defer聲明的時(shí)候,就當(dāng)作defer參數(shù)傳遞到defer函數(shù)中匿名函數(shù)
func main() {
/* 匿名函數(shù)切片初始化 */
fns := [](func(x int) int){
func(x int) int { return x + 1 },
func(x int) int { return x + 113 },
}
println(fns[1](100))
/* 結(jié)構(gòu)體初始化 */
d := struct {
fn func() string
}{
fn: func() string { return "Hello, World!" },
}
println(d.fn())
fc := make(chan func() string, 2)
fc <- func() string { return "Hello, World!" }
println((<-fc)())
}閉包
package main
import "fmt"
func test() func() {
x := 100
fmt.Printf("x (%p) = %d\n", &x, x)
return func() {
fmt.Printf("x (%p) = %d\n", &x, x)
}
}
func main() {
f := test()
f()
}輸出:
x (0xc42007c008) = 100
x (0xc42007c008) = 100
到此這篇關(guān)于golang defer 閉包 匿名函數(shù)的文章就介紹到這了,更多相關(guān)golang defer 匿名函數(shù)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
go語言調(diào)用c語言的so動(dòng)態(tài)庫的實(shí)現(xiàn)
在Go語言開發(fā)過程中,有時(shí)需要調(diào)用C或C++編寫的so動(dòng)態(tài)庫,本文介紹了如何在Go語言中調(diào)用so庫的步驟和注意事項(xiàng),包括環(huán)境準(zhǔn)備、編譯生成.so文件、Go文件編寫、以及可能遇到的問題和解決方法,感興趣的可以了解一下2024-10-10
GoLang strings.Builder底層實(shí)現(xiàn)方法詳解
自從學(xué)習(xí)go一個(gè)月以來,我多少使用了一下strings.Builder,略有心得。你也許知道它,特別是你了解bytes.Buffer的話。所以我在此分享一下我的心得,并希望能對(duì)你有所幫助2022-10-10
Go select 死鎖的一個(gè)細(xì)節(jié)
這篇文章主要給大家分享的是Go select 死鎖的一個(gè)細(xì)節(jié),文章先是對(duì)主題提出問題,然后展開內(nèi)容,感興趣的小伙伴可以借鑒一下,希望對(duì)你有所幫助2021-10-10
gin項(xiàng)目部署到服務(wù)器并后臺(tái)啟動(dòng)的步驟
本文主要介紹了gin項(xiàng)目部署到服務(wù)器并后臺(tái)啟動(dòng)的步驟,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-02-02
Go語言基礎(chǔ)模板設(shè)計(jì)模式示例詳解
這篇文章主要為大家介紹了Go語言基礎(chǔ)設(shè)計(jì)模式之模板模式的示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步2021-11-11
手把手教你如何在Goland中創(chuàng)建和運(yùn)行項(xiàng)目
歡迎來到本指南!我們將手把手地教您在Goland中如何創(chuàng)建、配置并運(yùn)行項(xiàng)目,通過簡(jiǎn)單的步驟,您將迅速上手這款強(qiáng)大的集成開發(fā)環(huán)境(IDE),輕松實(shí)現(xiàn)您的編程夢(mèng)想,讓我們一起開啟這段精彩的旅程吧!2024-02-02

