defer特性:
- 关键字 defer 用于注册延迟调用。
- 这些调用直到 return 前才被执。因此,可以用来做资源清理。
- 多个defer语句,按先进后出的方式执行。
- defer语句中的变量,在defer声明时就决定了。
defer用途:
- 关闭文件句柄
- 锁资源释放
- 数据库连接释放
package main
import "fmt"
func main() {
var users [5]struct{}
for i := range users {
defer fmt.Println(i)
}
}
输出:4 3 2 1 0 ,defer 是先进后出
package defer_test
import (
"fmt"
"testing"
)
func TestDefer1(t * testing.T) {
var users [5]struct{}
for i := range users {
defer func() { fmt.Println(i) }()
}
}
输出结果:4 4 4 4 4 是否在想一个问题,输出结果不是 4 3 2 1 0 , 由于是闭包用到的变量 i 在执行的时候已经变成了4 , 所以输出全部是 4, 如何正常输出。4 3 2 1 0 ?不用闭包,换成函数即可。
func TestDefer2(t *testing.T) {
var users [5]struct{}
for i := range users {
defer Print(i)
}
}
func Print(i int) {
fmt.Println(i)
}
函数的输出结果是 :4 3 2 1 0
再看个结构体的例子
func (t *Users) GetName(){
fmt.Println(t.name)
}
func TestDefer3(t * testing.T){
list := []Users{{"乔峰"}, {"慕容复"},{"欧阳克"}}
for _, t := range list {
defer t.GetName()
}
}
发现没,输出的结果竟然是 欧阳克 欧阳克 欧阳克
不是欧阳克 慕容复 乔峰
如何要输出 :欧阳克 慕容复 乔峰
写个函数:
type Users struct {
name string
}
func (t *Users) GetName(){
fmt.Println(t.name)
}
func GetName(t Users){
t.GetName()
}
func TestDefer4(t *testing.T) {
list := []Users{{"乔峰"}, {"慕容复"},{"欧阳克"}}
for _, t := range list {
defer GetName(t)
}
}
函数输出结果:欧阳克 慕容复 乔峰
如果不想多写一个函数,输出 欧阳克 慕容复 乔峰
要怎么搞?复制一份即可
type Users struct {
name string
}
func (t *Users) GetName() {
fmt.Println(t.name)
}
func TestDefer5(t *testing.T) {
list := []Users{{"乔峰"}, {"慕容复"}, {"欧阳克"}}
for _, t := range list {
t1 := t
defer t1.GetName()
}
}
输出结果:欧阳克 慕容复 乔峰
defer 后面的语句在执行的时候,函数调用的参数会保存起来,复制一份,但是不执行。
多个 defer 注册,采用的是 FILO 先进后出的方式,哪怕函数发生错误, 这些调用依然会被执行。
func users(i int) {
defer println("北丐")
defer println("南帝")
defer func() {
println("西毒")
println(10 / i) // 异常未被捕获,逐步往外传递,最终终止进程。
}()
defer println("东邪")
}
func TestDefer6(t *testing.T) {
users(0)
println("武林高手排行榜,这里不会被输出")
}
defer 与 return
在有命名返回值的函数中, 执行 return "风清扬"的时候实际上已经将 s 的值重新赋值为 风清扬
func Users2() (s string) {
s = "乔峰"
defer func() {
fmt.Println("延迟执行后:" + s)
}()
return "清风扬"
}
func TestDefer7(t *testing.T) {
Users2() // 输出:延迟执行后:清风扬
}
输出结果:
延迟执行后:清风扬
--- PASS: TestDefer7 (0.00s)
PASS
欢迎关注公众号:程序员开发者社区
关注我们,了解更多