Golang中的匿名函数、闭包、defer、panic、recover

匿名函数

1
2
3
4
5
6
7
8
9
10
package main

import "fmt"

func main() {
f := func() {
fmt.Println("test")
}
f()
}

闭包

下面代码中,输出的三个x的地址一定是一样的,它们引用同一个变量。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package main

import "fmt"

func main() {
f := closure(10)
fmt.Println(f(1))
fmt.Println(f(2))
}

func closure(x int) func(int) int {
fmt.Println(&x)
return func(y int) int {
fmt.Println(&x)
return x + y
}
}

/* possible output:
0xc000060068
0xc000060068
11
0xc000060068
12
*/

defer

  • 执行方式类似其它语言中的析构函数,在函数体执行结束后按照调用顺序的相反顺序逐个执行
  • 即使函数发生严重错误也会执行
  • 支持匿名函数的调用
  • 常用于资源清理、文件关闭、解锁以及记录时间等操作
  • 通过与匿名函数配合可在return之后修改函数计算结果
  • 如果函数体内某个变量作为defer时匿名函数的参数,则在定义defer时即已经获得了拷贝,否则则是引用某个变量的地址

下面这个代码中,defer时i就传值进去了。所以输出210

1
2
3
4
5
6
7
8
9
package main

import "fmt"

func main() {
for i := 0; i < 3; i++ {
defer fmt.Print(i)
}
}

下面这个代码中,由于闭包中的i是对main函数中局部变量i的引用。defermain函数结束后执行,而main函数结束时i的值已经为3。所以输出3次3

1
2
3
4
5
6
7
8
9
10
11
package main

import "fmt"

func main() {
for i := 0; i < 3; i++ {
defer func() {
fmt.Println(i)
}()
}
}

下面这个代码中,闭包里每一次传递的string事实上都不是同一个。所以输出的是ans2 ans1 ans0

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package main

import (
"fmt"
"strconv"
)

func main() {
for i := 0; i < 3; i++ {
var t string = "ans" + strconv.Itoa(i)
defer func() {
fmt.Print(t + " ")
}()
}
}

defer配合panic与recover

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
package main

import "fmt"

func main() {
f1()
f2()
f3()
}

func f1() {
fmt.Println("func f1")
}

func f2() {
// defer 一定要在 panic 之前, 因为 panic 触发时
// panic 所在函数就会立刻终止并倒序调用所有已经存在的defer
// 若 defer 在 panic 之后, 程序根本不会知道后面有 defer
defer func() {
if err := recover(); err != nil {
fmt.Println("err =", err)
fmt.Println("recover in f2 (first)")
}
}()
defer func() {
if err := recover(); err != nil {
fmt.Println("err =", err)
fmt.Println("recover in f2 (second)")
}
}()
panic("panic in f2")
}

func f3() {
fmt.Println("func f3")
}
/* output:
func f1
err = panic in f2
recover in f2 (second)
func f3
*/
Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×