分享
  1. 首页
  2. 文章

go语言defer使用

chuanheng · · 2228 次点击 · · 开始浏览
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

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(){;u2.Close()}() 
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的功能特性,也满足范围精确控制的条件!


有疑问加站长微信联系(非本文作者)

本文来自:博客园

感谢作者:chuanheng

查看原文:go语言defer使用

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

关注微信
2228 次点击
1 回复 | 直到 2000年01月01日 00:00:00
暂无回复
添加一条新回复 (您需要 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传

用户登录

没有账号?注册
(追記) (追記ここまで)

今日阅读排行

    加载中
(追記) (追記ここまで)

一周阅读排行

    加载中

关注我

  • 扫码关注领全套学习资料 关注微信公众号
  • 加入 QQ 群:
    • 192706294(已满)
    • 731990104(已满)
    • 798786647(已满)
    • 729884609(已满)
    • 977810755(已满)
    • 815126783(已满)
    • 812540095(已满)
    • 1006366459(已满)
    • 692541889

  • 关注微信公众号
  • 加入微信群:liuxiaoyan-s,备注入群
  • 也欢迎加入知识星球 Go粉丝们(免费)

给该专栏投稿 写篇新文章

每篇文章有总共有 5 次投稿机会

收入到我管理的专栏 新建专栏