从Go面试题看defer语义的底层原理和注意事项

面试题

defer
defer
  • A: 100
  • B: 102
  • C: 022
  • D: 011

这道题主要考察以下知识点:

deferdeferdeferNewFoo(p).Bar(p)NewFooBar

解析

我们再看看官方文档怎么说的:

Each time a "defer" statement executes, the function value and parameters to the call are evaluated as usual and saved anew but the actual function is not invoked.
Instead, deferred functions are invoked immediately before the surrounding function returns, in the reverse order they were deferred.
That is, if the surrounding function returns through an explicit return statement, deferred functions are executed after any result parameters are set by that return statement but before the function returns to its caller.
If a deferred function value evaluates to nil, execution panics when the function is invoked, not when the "defer" statement is executed.

官方文档的前两句话对我们求解本题至关重要,用中文来表述就是:

Adefer B(params)deferBdeferBA
defer
defer NewFoo(p).Bar(p)NewFoo(p)Bar
defer NewFoo(p).Bar(p)p

这道题求解过程如下:

代码执行结果
var x = 1定义一个整型变量x,值为1
var p = &x定义一个指针p,指向变量x
defer NewFoo(p).Bar(p)NewFoo(p)和参数p会被即时计算。NewFoo(p)的执行结果会打印1,指针p的值是变量x的内存地址,*p也就是变量x的值,Bar的调用会延后到main函数return之前执行
x = 2修改x的值为2
p = new(int)修改指针p的值,不再指向x,而是指向新的内存地址,该内存地址存的值是int的零值,也就是0
NewFoo(p)调用函数NewFoo,打印0。
main函数return之前,执行Bar方法,Bar的参数p的值在defer语句执行的时候就已经确定下来了,是变量x的内存地址,因此Bar方法打印的是变量x的值,也就是2

因此本题的运行结果是102,答案是B。

defer六大原则

defer
iideferdeferfffdeferdefer

思考题

思考下面这3道题的运行结果是什么?大家可以在评论区留下你们的答案或者参考我的vx。

题目1:程序运行结果是什么?

f(1, 2)

题目3:“test”会被打印么?


开源地址

文章和示例代码开源地址在GitHub: https://github.com/jincheng9/go-tutorial

公众号:coding进阶


defer的另外2道题目可以参考我知乎专栏或者vx公号,掌握defer所有注意事项。

好文推荐


References