随笔 - 217  文章 - 1  评论 - 48  阅读 - 64万

go语言 defer 你不知道的秘密!

go 语言的defer功能强大,对于资源管理非常方便,但是如果没用好,也会有陷阱哦.我们先来看几个例子.

例一: defer 是先进后出

  这个很自然,后面的语句会依赖前面的资源,因此如果先前面的资源先释放了,后面的语句就没法玩了.

1 func main() {
2     var whatever [5]struct{}
3 
4     for i := range whatever {
5         defer fmt.Println(i)
6     }
7 }

这个输出应该很明显,就是4 3 2 1 0

例二: defer 碰上闭包

func main() {
    var whatever [5]struct{}
    for i := range whatever {
        defer func() { fmt.Println(i) }()
    }

}

这个输出可能会超出某些人的意料,结果是4 4 4 4 4

其实go说的很清楚,我们一起来看看go spec如何说的

Each time a "defer" statement executes, the function value and parameters to the call are evaluated as usualand saved anew but the actual function is not invoked. 

也就是说函数正常执行,由于闭包用到的变量i在执行的时候已经变成4,所以输出全都是4.

例三: defer f.Close

这个大家用的都很频繁,但是go语言编程举了一个可能一不小心会犯错的例子.

复制代码
type Test struct {
    name string
}
func (t * Test) Close(){
    fmt.Println(t.name," closed");
}
func main(){
    ts:=[]Test{{"a"},{"b"},{"c"}}
    for _,t := range ts{
        defer  t.Close()
    }
}

复制代码

这个输出并不会像我们预计的输出c b a,而是输出c c c

可是按照前面的go spec中的说明,应该输出c b a才对啊.

那我们换一种方式来调用一下.

例四: 像例一一样的调用

复制代码
type Test struct {
    name string
}
func (t * Test) Close(){
    fmt.Println(t.name," closed");
}
func Close(t Test){
    t.Close()
}
func main(){
    ts:=[]Test{{"a"},{"b"},{"c"}}
    for _,t := range ts{
        Close(t)
    }
}

复制代码

这个时候输出的就是c b a

当然,如果你不想多写一个函数,也很简单,可以像下面这样,同样会输出c b a

例五:看似多此一举的声明

复制代码
type Test struct {
    name string
}
func (t * Test) Close(){
    fmt.Println(t.name," closed");
}
func main(){
    ts:=[]Test{{"a"},{"b"},{"c"}}
    for _,t := range ts{
        t2:=t
        t2.Close()
    }
}
复制代码

通过以上例子,结合

Each time a "defer" statement executes, the function value and parameters to the call are evaluated as usualand saved anew but the actual function is not invoked. 

这句话.可以得出下面的结论:

defer后面的语句在执行的时候,函数调用的参数会被保存起来,但是不执行.也就是复制了一份.但是并没有说struct这里的this指针如何处理,通过这个例子可以看出go语言并没有把这个明确写出来的this指针当作参数来看待.

posted on   baizx  阅读(6433)  评论(5编辑  收藏  举报
编辑推荐:
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具
· AI 智能体引爆开源社区「GitHub 热点速览」
· C#/.NET/.NET Core技术前沿周刊 | 第 29 期(2025年3.1-3.9)
< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

点击右上角即可分享
微信分享提示