• 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指针当作参数来看待.

  • 相关阅读:
    Python爬虫入门教程 43-100 百思不得姐APP数据-手机APP爬虫部分
    也谈PostgreSQL的Vacuum机制及其最佳实践
    django.core.exceptions.ImproperlyConfigured: Requested setting INSTALLED_APPS
    Error: Invalid CSS after
    win32-x64-64inding.node is not a valid Win32 application
    Error: Module did not self-register
    数据分析|如何利用BI工具,探索各商品的潜在关联价值
    Python爬虫入门教程 42-100 爬取儿歌多多APP数据-手机APP爬虫部分
    Retrofit的文件上传和进度提示
    Retrofit的文件上传和进度提示
  • 原文地址:https://www.cnblogs.com/baizx/p/5024547.html
Copyright © 2020-2023  润新知