文章目录
Go语言系列教程:https://blog.csdn.net/zhangpeterx/article/details/89040274
defer是Go语音中非常重要的一个关键字,需要深入的了解。
1.defer语句格式
defer后只能接函数,如:
defer func() {
fmt.Println("defer print")
}()
2.defer执行的时间
defer被称为延迟语句,在return函数执行前执行defer语句。
如:
package main
import "fmt"
func main() {
defer func() {
fmt.Println("defer print")
}()
fmt.Println("outer print")
}
输出结果如下:
outer print
defer print
3.defer语句的作用
defer语句设计的初衷是用来关闭或释放资源的。
如下:
func main() {
f, err := os.Create("test.file")
if err != nil {
panic("cannot create file")
}
defer f.Close()
// no matter what happens here file will be closed
// for sake of simplicity I skip checking close result
fmt.Fprintf(f, "hello")
}
4.defer语句执行的顺序
defer语句执行的顺序是先进后出,也就是栈。
先遇到的defer语句会把函数及其参数
压进栈中,最后再统一执行。
func main() {
for i := 0; i < 4; i++ {
defer fmt.Println(i)
}
}
结果如下:
3
2
1
0
如果把代码改为如下:
func main() {
for i := 0; i < 4; i++ {
defer func() {
fmt.Println(i)
}()
}
}
输出结果如下:
4
4
4
4
这是因为在运行到defer
语句时,i
并不是函数参数,是外部变量,所以会直接读取外部变量的值。
5.defer与return的value之间的关系
因为defer语句是延迟执行,那么就涉及到如果defer语句修改了return的value,那么return的结果到底是什么这个问题。
如果函数的返回值是有名变量,那么defer语句可以直接操作变量:
func c() (i int) {
defer func() { i++ }()
return 1
}
func main() {
fmt.Println("c return :", c())
}
输出:
c return : 2
具体过程是:
i=1
i++
return i
如果是无名变量,return最初的结果:
func c() int {
var i int = 0
defer func() { i++ }()
return i
}
func main() {
fmt.Println("c return :", c())
}
输出:
c return : 0
6.用defer进行代码跟踪
defer语句另一个用法是用来跟踪代码,如在函数开始和结束的时候打印相关信息:
package main
import "fmt"
func trace(s string) string {
fmt.Println("开始执行", s)
return s
}
func untrace(s string) {
fmt.Println("结束执行", s)
}
func a() {
defer untrace(trace("a"))
fmt.Println("a的逻辑代码")
}
func b() {
defer untrace(trace("b"))
fmt.Println("b的逻辑代码")
a()
}
func main() {
b()
}
输出结果如下:
开始执行 b
b的逻辑代码
开始执行 a
a的逻辑代码
结束执行 a
结束执行 b
7.defer一定会被执行吗?
不一定,如果你调用os.Exit()
,那么defer不会被执行。
参考:
- Use of defer in Go - Stack Overflow
- go - How does defer and named return value work? - Stack Overflow
转载:https://blog.csdn.net/zhangpeterx/article/details/101569212
查看评论