面试题
deferdeferpackage main
type Foo struct {
v int
}
func NewFoo(n *int) Foo {
print(*n)
return Foo{}
}
func (Foo) Bar(n *int) {
print(*n)
}
func main() {
var x = 1
var p = &x
defer NewFoo(p).Bar(p)
x = 2
p = new(int)
NewFoo(p)
}- 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)deferBdeferBAdeferdefer NewFoo(p).Bar(p)NewFoo(p)Bardefer NewFoo(p).Bar(p)p这道题求解过程如下:
因此本题的运行结果是102,答案是B。
defer六大原则
defer- defer后面跟的必须是函数或者方法调用,defer后面的表达式不能加括号。
defer (fmt.Println(1)) // 编译报错,因为defer后面跟的表达式不能加括号
- 被defer的函数或方法的参数的值在执行到defer语句的时候就被确定下来了。下面的例子,被defer的函数fmt.Println的参数i在执行到defer这一行的时候,i的值是0,fmt.Println的参数就被确定下来是0了,因此最终打印的结果是0,而不是1。
func a() {
i := 0
defer fmt.Println(i) // 最终打印0
i++
return
}
deferdeferfunc b() {
for i := 0; i < 4; i++ {
defer fmt.Print(i)
}
}
- 被defer的函数可以对defer语句所在的函数的命名返回值做读取和修改操作。下例中,被defer的函数func对defer语句所在的函数f的命名返回值result做了修改操作。 调用函数f,返回的结果是42。 执行顺序是函数f先把要返回的值6赋值给result,然后执行被defer的函数func,result被修改为42,然后函数f返回result给调用方,也就返回了42。
// f returns 42
func f() (result int) {
defer func() {
// result is accessed after it was set to 6 by the return statement
result *= 7
}()
return 6
}
deferdefer思考题
思考下面这3道题的运行结果是什么?大家可以在评论区留下你们的答案。想确认答案的也可以在我的wx公众号发送 defer 获取答案。
题目1:程序运行结果是什么?
package main
type T int
func (t T) M(n int) T {
print(n)
return t
}
func main() {
var t T
defer t.M(1).M(2)
t.M(3).M(4)
}
f(1, 2)package main
import "fmt"
type Add func(int, int) int
func main() {
var f Add
defer f(1, 2)
fmt.Println("end")
}
题目3:“test”会被打印么?
package main
import (
"fmt"
"os"
)
func test1() {
fmt.Println("test")
}
func main() {
defer test1()
os.Exit(0)
}
开源地址
文章和示例代码开源地址在GitHub: https://github.com/jincheng9/go-tutorial
公众号:coding进阶