golang基础小记(12)——defer

defer语句

Go语言中的defer语句会将其后面跟随的函数推迟到外层函数返回之后执行。推迟调用的函数其参数会立即求值,但直到外层函数返回前该函数都不会被调用。推迟的函数调用会被压入一个栈中,当外层函数返回时,被推迟的函数会按照后进先出的顺序调用。
defer语句后面只能跟函数调用。
示例:

a := 1
b := 2
defer fmt.Println(1, a + b) // 推迟的函数参数会立即赋值,后续改变参数值不会影响结果
defer func() { // 该函数没有参数,如果函数内部使用了外层函数的变量,那么外层函数改变变量值会对结果产生影响
	fmt.Println(2, a) // 这里 a == 2
}()
a = 2
b = 3
defer fmt.Println(3, a + b) // 后推迟的语句先输出结果
fmt.Println("end")

输出:

end
3 5
2 2
1 3

由于defer语句延迟调用的特性,所以defer语句能非常方便的处理资源释放问题。比如:资源清理、文件关闭、解锁及记录时间等。

defer执行时机

  1. 对返回值进行赋值
  2. 执行defer语句
  3. 执行RET指令(函数返回)

这里需要区分一下函数返回值命名和不命名的情况。当返回值命名时,defer语句可以对返回值进行修改,在判断返回值时需要注意defer语句;当返回值没有命名时,defer语句不会影响返回值。
示例:

func test1() int { // 返回值无命名
	x := 300
	defer func() {
		x = 100 // 此时x=300早就赋值给了返回值,这里只是改变x的值,与返回值无关
	}()
	return x
}

func test2() (x int) { //返回值有命名
	x = 300
	defer func() {
		x = 100 // 这里的x就是返回值,改变x就是直接改变返回值,如果改为x++,返回值为301
	}()
	return
}

func test3() (x int) {
	x = 300
	defer func(x int) { 
		x = 100 // 这里的x作为函数的参数,与返回值x不是同一个参数,所以对返回值没有影响
	}(x)
	return
}

func main() {
	fmt.Println(test1()) // 300
	fmt.Println(test2()) // 100
	fmt.Println(test3()) // 300
}

面试题

func calc(index string, a, b int) int {
	ret := a + b
	fmt.Println(index, a, b, ret)
	return ret
}

func main() {
	x := 1
	y := 2
	defer calc("AA", x, calc("A", x, y))
	x = 10
	defer calc("BB", x, calc("B", x, y))
	y = 20
}

输出:

A 1 2 3
B 10 2 12
BB 10 12 22
AA 1 3 4

因为defer语句推迟的函数的参数会立即求值,所以第一句defer语句先计算xcalc("A", x, y),传入的x = 1, y = 2,第二句同理,只是传入的x的值变成了10。
参考1参考2参考3

猜你喜欢

转载自blog.csdn.net/m0_37710023/article/details/107593374