golang defer 匿名函数
@航空母舰 人气:0defer用于资源的释放,会在函数返回之前进行调用。如果有多个defer表达式,调用顺序类似于栈,越后面的defer表达式越先被调用。
defer的触发时机
- 包裹着defer语句的函数返回时
- 包裹着defer语句的函数执行到最后时
- 当前goroutine发生Panic时
当前goroutine发生Panic时
//输出结果:return前执行defer func f1() { defer fmt.Println("return前执行defer") return } //输出结果:函数执行 // 函数执行到最后 func f2() { defer fmt.Println("函数执行到最后") fmt.Println("函数执行") } //输出结果:panic前 第一个defer在Panic发生时执行,第二个defer在Panic之后声明,不能执行到 func f3() { defer fmt.Println("panic前") panic("panic中") defer fmt.Println("panic后") }
defer,return,返回值的执行顺序
- 先给返回值赋值
- 执行defer语句
- 包裹函数return返回
func f1() int { //匿名返回值 var r int = 6 defer func() { r *= 7 }() return r } func f2() (r int) { //有名返回值 defer func() { r *= 7 }() return 6 } func f3() (r int) { //有名返回值 defer func(r int) { r *= 7 }(r) return 6 }
f1的执行结果是6, f2的执行结果是42,f3的执行结果是6
最后看example3。它改写后变成
func f1() (r int) { r = 6 //给返回值赋值 func(r int) { //这里改的r是传值传进去的r,不会改变要返回的那个r值 r *= 7 }(r) return //空的return }
f1的结果是6。f1是匿名返回值,匿名返回值是在return执行时被声明,因此defer声明时,还不能访问到匿名返回值,defer的修改不会影响到返回值。
f2先给返回值r赋值,r=6,执行defer语句,defer修改r, r = 42,然后函数return。
f3是有名返回值,但是因为r是作为defer的传参,在声明defer的时候,就进行参数拷贝传递,所以defer只会对defer函数的局部参数有影响,不会影响到调用函数的返回值。
闭包与匿名函数
匿名函数:没有函数名的函数。函数也是一种类型,一个函数可以赋值给变量
闭包:可以使用另外一个函数作用域中的变量的函数。闭包复制的是原对象指针,这就很容易解释延迟引用现象。
for i := 0; i <= 3; i++ { defer func() { fmt.Print(i) } } //输出结果时 3,3,3,3 因为defer函数的i是对for循环i的引用,defer延迟执行,for循环到最后i是3,到defer执行时i就是3 for i := 0; i <= 3; i++ { defer func(i int) { fmt.Print(i) }(i) } //输出结果时 3,2,1,0 因为defer函数的i是在defer声明的时候,就当作defer参数传递到defer函数中
匿名函数
func main() { /* 匿名函数切片初始化 */ fns := [](func(x int) int){ func(x int) int { return x + 1 }, func(x int) int { return x + 113 }, } println(fns[1](100)) /* 结构体初始化 */ d := struct { fn func() string }{ fn: func() string { return "Hello, World!" }, } println(d.fn()) fc := make(chan func() string, 2) fc <- func() string { return "Hello, World!" } println((<-fc)()) }
闭包
package main import "fmt" func test() func() { x := 100 fmt.Printf("x (%p) = %d\n", &x, x) return func() { fmt.Printf("x (%p) = %d\n", &x, x) } } func main() { f := test() f() }
输出:
x (0xc42007c008) = 100
x (0xc42007c008) = 100
加载全部内容