面试题
defer
defer
package 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)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
defer (fmt.Println(1)) // 编译报错,因为defer前面跟的表达式不能加括号
func a() {
i := 0
defer fmt.Println(i) // 最终打印0
i++
return
}
func b() {
for i := 0; i < 4; i++ {
defer fmt.Print(i)
}
}
// 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
}
思考题
思考上面这3道题的运行后果是什么?大家能够在评论区留下你们的答案。
题目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进阶
集体网站:https://jincheng9.github.io/
知乎:https://www.zhihu.com/people/thucuhkwuji
好文举荐
- 被defer的函数肯定会执行么?
- Go有援用变量和援用传递么?map,channel和slice作为函数参数是援用传递么?
- new和make的应用区别是什么?
- 一文读懂Go匿名构造体的应用场景
- 官网教程:Go泛型入门
- 一文读懂Go泛型设计和应用场景
- Go Quiz: 从Go面试题看slice的底层原理和注意事项
- Go Quiz: 从Go面试题看channel的注意事项
- Go Quiz: 从Go面试题看分号规定和switch的注意事项
References
- https://go101.org/quizzes/def…
- https://github.com/jincheng9/…
- https://golang.google.cn/ref/…