【注意】最后更新于 December 19, 2019,文中内容可能已过时,请谨慎使用。
defer特性
defer
是在 return
之后执行标记代码行, 直观一点就是函数从上往下一行行执行代码, 遇到defer跳过, return
之后, 再从下往上依次执行refer
举一个例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
package main
import (
"log"
"time"
)
func main() {
test()
}
func test() {
for i := 0; i < 5; i++ {
defer func(index int) {
log.Printf("i: %d, index: %d \n", i, index)
}(i)
}
}
|
输出:
1
2
3
4
5
|
2019/12/18 17:11:03 i: 5, index: 4
2019/12/18 17:11:03 i: 5, index: 3
2019/12/18 17:11:03 i: 5, index: 2
2019/12/18 17:11:03 i: 5, index: 1
2019/12/18 17:11:03 i: 5, index: 0
|
i
是外部变量, 在执行defer
的时候, 已经运行完毕for
循环, 那么i
此时的值就一直是5了
index
是函数内部变量, 是在运行时传入的, 变量值被拷贝到函数当中, 且最先defer
的最后执行, 所以看到了 4,3,2,1,0
由于defer中的变量在之前运行时都已经设置好了, 有些日志收集类的方法也可以使用它
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
|
package main
import (
"log"
"time"
)
func main() {
bigSlowOperation("test input")
}
func bigSlowOperation(input interface{}) (output interface{}) {
defer trace("bigSlowOperation", input)()
// ...lots of work…
time.Sleep(2 * time.Second) // simulate slow
output = "result"
log.Println("done")
return
}
func trace(funcName string, args ...interface{}) func() {
start := time.Now()
log.Printf("enter %s", funcName)
return func() {
log.Printf("func args: %s \n", args)
log.Printf("exit %s (%s)", funcName, time.Since(start))
}
}
|
使用场景一: 延迟释放资源
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
func CopyFile(dstName, srcName string) (written int64, err error) {
src, err := os.Open(srcName)
if err != nil {
return
}
defer src.Close()
dst, err := os.Create(dstName)
if err != nil {
return
}
defer dst.Close()
return io.Copy(dst, src)
}
|
这样把开启和关闭资源的函数写一起, 减少开发时的心智负担
使用场景二: recover
go 里面没有 try catch
, 但是有 painc recover
, 这个是配合defer
才能使用的
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
package main
import (
"fmt"
)
func main() {
defer func() {
if ok := recover(); ok != nil {
fmt.Println("recover")
}
}()
panic("error")
}
|
参考
文章作者
GPF
上次更新
2019-12-19
(881ec07)