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

匿名函数

package main

import "fmt"

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

闭包

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

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

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

package main

import "fmt"

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

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

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

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
*/
原文地址:https://www.cnblogs.com/sandychn/p/12421988.html