GO Rountine 闭包 问题

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第3天,点击查看活动详情

GO Rountine 闭包 问题

case1

看下面代码,可以猜测下输出结果是啥?

a := []int{1, 2, 3}
	for _, cur := range a {
		go func() {
			doPrint(cur)
		}()
	}
复制代码

执行结果:

=== RUN   TestSlice
3
3
3
--- PASS: TestSlice (3.00s)
PASS
复制代码

发现会有问题,为啥每次打印的都是3, 在循环中 cur 是一个单变量,表示每个数组元素的元素值,闭包都只绑定到一个变量,因为协程可能在循环结束后还没有开始执行。因此每个循环都是最后一个值。

可在for循环代码块内把当前迭代的变量值保存到一个局部变量中 改成如下即可:

a := []int{1, 2, 3}
	for _, cur := range a {
    v := cur
		go func() {
			doPrint(v)
		}()
	}
复制代码

case 2

一个解决方法是把当前的迭代变量作为匿名goroutine的参数。

func TestSlice(t *testing.T) {
	a := []int{1, 2, 3}
	for _, cur := range a {
		go func(d int) {
			doPrint(d)
		}(cur)
	}
复制代码

执行结果:

=== RUN   TestSlice
3
1
2
--- PASS: TestSlice (3.00s)
PASS
复制代码

case 3

a := []int{1, 2, 3}
	for _, cur := range a {
		go doPrint(cur)
	}
复制代码

执行结果:

=== RUN   TestSlice
3
1
2
--- PASS: TestSlice (3.00s)
PASS
复制代码

为啥这个结果不是和第一个一致的呢?其实这个 case3 和 case2 是一个意思,都是通过匿名函数的方式传承。调用每个闭包是将 cur 作为参数传递给闭包。cur 在每次循环时都被重新赋值,并将每个协程的 cur 放置在栈中,所以当协程最终被执行时,每个索引值对协程都是可用的,会输出不同的值。

附赠:Go 基础类型

类型 长度(字节) 默认值 说明
bool 1 false
byte 1 0 uint8
rune 4 0 Unicode Code Point, int32
int, uint 4或8 0 32 或 64 位
int8, uint8 1 0 -128 ~ 127, 0 ~ 255,byte是uint8 的别名
int16, uint16 2 0 -32768 ~ 32767, 0 ~ 65535
int32, uint32 4 0 -21亿~ 21亿, 0 ~ 42亿,rune是int32 的别名
int64, uint64 8 0
float32 4 0.0
float64 8 0.0
complex64 8
complex128 16
uintptr 4或8 以存储指针的 uint32 或 uint64 整数
array 值类型
struct 值类型
string “” UTF-8 字符串
slice nil 引用类型
map nil 引用类型
channel nil 引用类型
interface nil 接口
function nil 函数

猜你喜欢

转载自juejin.im/post/7127652378156728350