您的位置:首页 > 编程语言 > Go语言

go语言defer使用 .

2015-06-09 15:55 701 查看


[title3]
defer[/title3]

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哪样准确。

[plain]
view plaincopyprint?

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]$
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添加内部代码区:

[plain]
view plaincopyprint?

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 !") }
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呢?

[plain]
view plaincopyprint?

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()<PRE class=plain name="code"> func() {
defer u2.Close()
// u2 do somthing
}()</PRE> time.Sleep(10 * time.Second) fmt.Println("Done !")}func f(u *User) { defer u.Close() // u1 do gomething}

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()<div class="dp-highlighter bg_plain"><div class="bar"><div class="tools"><strong>[plain]</strong> <a target=_blank class="ViewSource" title="view plain" href="/article/8258296.html#">view plain</a><a target=_blank class="CopyToClipboard" title="copy" href="/article/8258296.html#">copy</a><a target=_blank class="PrintSource" title="print" href="/article/8258296.html#">print</a><a target=_blank class="About" title="?" href="/article/8258296.html#">?</a><a target=_blank href="/article/8258296.html"></a></div></div><ol><li class="alt"><span><span>func() {  </span></span></li><li><span>         defer u2.Close()  </span></li><li class="alt"><span>         // u2 do somthing  </span></li><li><span>}()  </span></li></ol></div><pre style="DISPLAY: none" class="plain" name="code">        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的功能特性,也满足范围精确控制的条件!

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: