defer 语句会延迟函数的执行直到上层函数返回。 延迟调用的参数会立刻生成,但是在上层函数返回前函数都不会被调用。
延迟的函数调用被压入一个栈中。当函数返回时,会按照后进先出的顺序调用被延迟的函数调用
func main() {
defer fmt.Println("world")
fmt.Println("hello")
}
// 先输出 hello, 再输出 world
题一
func hello(i int) {
fmt.Println(i)
}
func main() {
i := 5
defer hello(i)
i = i + 10
}
// 输出:5
// hello() 函数的参数在执行 defer 语句的时候会保存一份副本
题二
f1, f2, f3 各返回什么
func f1() (r int) {
defer func() {
r++
}()
return r
}
func f2() (r int) {
t := 5
defer func() {
t = t + 5
}()
return t
}
func f3() (r int) {
defer func(r int) {
r = r + 5
}(r)
return 1
}
// f1() 返回 1
// 按三部拆开:
// r初始化: r = 0;
// func: r++: r = 1;
// 再返回 return r
// f2() 返回 5
// 按三部拆开:r = 0, t = 5; r = t; func: t = t + 5; return r
// f3() 返回 1
// 按三部拆开:r = 0; r = 1; func:r=r+5; return
题三
func b() {
for i := 0; i < 4; i++ {
defer fmt.Print(i)
}
}
// 输出: 3210
type Person struct {
age int
}
func main() {
person := &Person{28}
// #1.
defer fmt.Println(person.age)
// #2.
defer func(p *Person) {
fmt.Println(p.age)
}(person)
// #3.
defer func() {
fmt.Println(person.age)
}()
person.age = 29 // #A
}
// 输出 29 29 28
// 输出顺序:#3 #2 #1.
// #1 存的28, #2 存的指针,后面修改为29,调用时29 #3 存了一个闭包,调用时29
// 如果把 #A 处改成:person = &Person{29}
// 那么结果为:29 28 28
题四
func calc(index string, a, b int) int {
ret := a + b
fmt.Println(index, a, b, ret)
return ret
}
func main() {
a := 1
b := 2
defer calc("1", a, calc("10", a, b))
a = 0
defer calc("2", a, calc("20", a, b))
b = 1
}
// 输出:
// 10 1 2 3
// 20 0 2 2
// 2 0 2 2
// 1 1 3 4
题五
func f(n int) (r int) {
defer func() {
r += n
recover()
}()
var f func()
defer f()
f = func() {
r += 2
}
return n + 1
}
func main() {
fmt.Println(f(3))
}
// 还是按三部拆开
1. r = n + 1 (即 r = 4)
2. 接着执行第二个 defer,由于此时 f() 未定义,引发异常
执行第一个 defer,异常被 recover(),程序正常执行 r += n (即 r = 7)
3. return