匿名函数
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 } }
|
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
的引用。defer
在main
函数结束后执行,而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 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") }
|