当执行到该条语句时,函数和参数表达式得到计算,但直到包含该defer语句的函数执行完毕时,defer后的函数才会被执行,不论包含defer语句的函数是通过return正常结束,还是由于panic导致的异常结束。你可以在一个函数中执行多条defer语句,它们的执行顺序与声明顺序相反。defer语句经常被用于处理成对的操作,如打开、关闭、连接、断开连接、加锁、释放锁。通过defer机制,不论函数逻辑多复杂,都能保证在任何执行路径下,资源被释放。释放资源的defer应该直接跟在请求资源的语句后。
package ioutil
func ReadFile(filename string) ([]byte, error) {
f, err := os.Open(filename)
if err != nil {
return nil, err
}
defer f.Close()
return ReadAll(f)
}
被延迟执行的匿名函数甚至可以修改函数返回给调用者的返回值:defer后的函数不带参数,就会延后处理,如果是带参数,会实时计算。
func double(x int) (result int) {
defer func() { fmt.Printf("double(%d) = %d\n", x,result) }()
return x + x
}
func triple(x int) (result int) {
defer func() { result += x }()
return double(x)
}
fmt.Println(triple(4)) // "12"
输出
double(4) = 8
12
defer有三个规则
1、defer声明时,其后面函数参数会被实时解析。
package main
import "fmt"
func pr(i int) {
fmt.Println("pr", i)
}
func main() {
var i int = 1
defer pr(i) //有参数,所以i就是1
i++
defer func() {
fmt.Println("main", i) //没参数,所以调用它的时候i是3
}()
i++
}
输出
main 3
pr 1
2、defer执行顺序为先进后出,从上面例子中可以知道最下面的先执行
3、defer可以读取函数的有名返回值
package main
import "fmt"
func fun1() (i int) {
defer func() {
i = i + 10
}()
return 0 //返回的变量i,正好和函数内部对应。
}
func main() {
fmt.Println(fun1())
}
输出
10