简介

参考博客:

Golang的闭包

函数在Golang中是“一等公民”,因此关于函数的特性必须要掌握号,闭包可以看成函数的高阶应用,是Golang高级开发的必备技能。

匿名函数

“一等公民”意味着函数可以像普通的类型(整型、字符串等)一样进行赋值、作为函数的参数传递、作为函数的返回值等。Golang的函数只能返回匿名函数!
代码实例:

var f = func(int) {}

func main() {
	f = func(i int) {
		fmt.Println(i)
	}
	f(2)
	f = func(i int) {
		fmt.Println(i * i * i)
	}
	f(2)
}
/*
输出:
2
8
*/
fff
闭包

闭包是匿名函数与匿名函数所引用环境的组合。匿名函数有动态创建的特性,该特性使得匿名函数不用通过参数传递的方式,就可以直接引用外部的变量。这就类似于常规函数直接使用全局变量一样,个人理解为:匿名函数和它引用的变量以及环境,类似常规函数引用全局变量处于一个包的环境。

func main() {
	n := 0
	f := func() int {
		n += 1
		return n
	}
	fmt.Println(f())  // 别忘记括号,不加括号相当于地址
	fmt.Println(f())
}
/*
输出:
1
2
*/

在上述代码中,

n := 0
f := func() int {
	n += 1
	return n
}
f
闭包作为函数返回值

匿名函数作为返回值,不如理解理解为闭包作为函数的返回值,如下代码:

func Increase() func() int {
	n := 0
	return func() int {
		n++
		return n
	}
}

func main() {
	in := Increase()
	fmt.Println(in())
	fmt.Println(in())
}
/*
输出:
1
2
*/
inin
Golang并发中的闭包

Go语言的并发时,一定要处理好循环中的闭包引用的外部变量。如下代码:

func main() {
	runtime.GOMAXPROCS(runtime.NumCPU())

	var wg sync.WaitGroup
	for i := 0; i < 5; i++ {
		wg.Add(1)
		go func() {
			fmt.Println(i)
			wg.Done()
		}()
	}
	wg.Wait()
}
输出结果:
5
5
5
5
5
igogoroutinegoroutinegoroutineigoroutinegoroutinegoroutinegoroutineiigoroutinei==5

我们可以使用循环的延时在验证上述说法:

func main() {
	runtime.GOMAXPROCS(runtime.NumCPU())

	var wg sync.WaitGroup
	for i := 0; i < 5; i++ {
		wg.Add(1)
		go func() {
			fmt.Println(i)
			wg.Done()
		}()
		time.Sleep(1 * time.Second)   // 设置时间延时1秒
	}
	wg.Wait()
}
/*
输出结果:
0
1
2
3
4
*/
goroutine

在实际的工程中,不可能进行延时,这样就没有并发的优势,一般采取下面两种方法:

  1. 共享的环境变量作为函数参数传递:
func main() {
	runtime.GOMAXPROCS(runtime.NumCPU())

	var wg sync.WaitGroup
	for i := 0; i < 5; i++ {
		wg.Add(1)
		go func(i int) {
			fmt.Println(i)
			wg.Done()
		}(i)
	}
	wg.Wait()
}
/*
输出:
4
0
3
1
2
*/
goroutinegoroutinei

2.使用同名的变量保留当前的状态

func main() {
	runtime.GOMAXPROCS(runtime.NumCPU())

	var wg sync.WaitGroup
	for i := 0; i < 5; i++ {
		wg.Add(1)
		i := i       // 注意这里的同名变量覆盖
		go func() {
			fmt.Println(i)
			wg.Done()
		}()
	}
	wg.Wait()
}
/*
输出结果:
4
2
0
3
1
结果顺序原因同1
*/
iiiigoroutine