go语言defer使用

defer

Go语言中有种不错的设计,即延迟(defer)语句,你可以在函数中添加多个defer语句。当函数执行到最后时,这些defer语句会按照逆序执行,最后该函数返回。特别是当你在进行一些打开资源的操作时,遇到错误需要提前返回,在返回前你需要关闭相应的资源,不然很容易造成资源泄露等问题。如下代码所示,我们一般写打开一个资源是这样操作的:

func ReadWrite() bool {
    file.Open("file")
// 做一些工作
    if failureX {
        file.Close()
        return false
    }

    if failureY {
        file.Close()
        return false
    }

    file.Close()
    return true
}

我们看到上面有很多重复的代码,Go的defer有效解决了这个问题。使用它后,不但代码量减少了很多,而且程序变得更优雅。在defer后指定的函数会在函数退出前调用。

func ReadWrite() bool {
    file.Open("file")
    defer file.Close()
    if failureX {
        return false
    }
    if failureY {
        return false
    }
    return true
}

如果有很多调用defer,那么defer是采用后进先出模式,所以如下代码会输出4 3 2 1 0

for i := 0; i < 5; i++ {
    defer fmt.Printf("%d ", i)
}


defer 给我的第一印象就是,类似java中的

try {

}finally {

}

我目前的理解就是,在函数块中使用defer,就是函数对应的有一个栈空间,先进后出。需要函数结束后调用栈,来出发defer操作。

如果,一个对象的创建,很消耗内存,需要及时关闭,defer无法像try finnaly哪样准确。

package main

import "fmt"
import "time"

type User struct {
        username string
}

func (this *User) Close() {
        fmt.Println(this.username, "Closed !!!")
}

func main() {
        u1 := &User{"jack"}
        defer u1.Close()
        u2 := &User{"lily"}
        defer u2.Close()

        time.Sleep(10 * time.Second)

        fmt.Println("Done !")

}
[vicky@localhost goroutine]$


[vicky@localhost goroutine]$ go run deferTest1.go
Done !
lily Closed !!!
jack Closed !!!
[vicky@localhost goroutine]$


实际上,线程Sleep的10秒,u1,和u2早就可以Close()了,但却需要依赖main()函数的结束,才能defer执行。

那么尝试给defer添加内部代码区:


package main

import "fmt"
import "time"

type User struct {
        username string
}

func (this *User) Close() {
        fmt.Println(this.username, "Closed !!!")
}

func main() {
        {
                // 即便加了代码快范围,依旧也要主函数体结束才执行defer
                u1 := &User{"jack"}
                defer u1.Close()
        }
        u2 := &User{"lily"}
        defer u2.Close()

        time.Sleep(10 * time.Second)

        fmt.Println("Done !")

}

Done !
lily Closed !!!
jack Closed !!!
[vicky@localhost goroutine]$


依旧defer的执行在Done!后。那么如何才能达到try finally 哪样准确的Close呢?

package main

import "fmt"
import "time"

type User struct {
        username string
}

func (this *User) Close() {
        fmt.Println(this.username, "Closed !!!")
}

func main() {
        u1 := &User{"jack"}
        f(u1) // 这样的方式,u1才会不依赖main函数的执行

        // 这样的方式,u2也不会依赖main函数的执行
        u2 := &User{"lily"}
        // m := func() {
        //         defer u2.Close()
        //         // u2 do somthing
        // }
        // m()
        func() {
                 defer u2.Close()
                 // u2 do somthing
        }()
time.Sleep(10 * time.Second) fmt.Println("Done !")}func f(u *User) { defer u.Close() // u1 do gomething}

[vicky@localhost goroutine]$ go run deferTest3.go
jack Closed !!!
lily Closed !!!
Done !


这样的使用方式,视乎不太合理,但却有存在的必要性。大多数情况下,可以用于 u1,u2  之类非常消耗内存,或者cpu,其后执行时间过程且没有太多关联的情况。既保留了defer的功能特性,也满足范围精确控制的条件!




  • 11
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值