Go Loop 使用存在的坑

118 阅读1分钟

Loop 是日常开发过程中经常遇到的问题,但是其中也有一些注意点需要关注。

循环中使用闭包

现由如下代码:

func TestFunBiBao(t *testing.T) {
	data := []string{"one", "two", "three"}
	for _, v := range data {
		go func() {
			fmt.Println(v)
		}()
	}
	time.Sleep(3 * time.Second)
	//goroutines print: three, three, three
}

我们可能会预期输出结果是:

one
two
three

然而实际

=== RUN   TestFunBiBao
three
three
three
--- PASS: TestFunBiBao (3.00s)
PASS

case 2 LOOP中对元素是指针类别的数组(slice)进行append操作,须确保append对象的指针在LOOP被正确更新

对数据循环进行增添元素, 需确保有更新效性

type Object struct {
	Index int
}
//targetList的元素.Index 的输出结果: [9, 9, 9, 9, 9, 9, 9, 9, 9, 9]
func TestObjLoop(t *testing.T) {
	var targetList []*Object // 指针类型的
	var pObj *Object
	pObj = &Object{}
	for loopCnt := 0; loopCnt < 10; loopCnt++ {
		pObj.Index = loopCnt
		targetList = append(targetList, pObj)
	}
	for _, obj := range targetList {
		fmt.Println(obj.Index)
	}
}

实际输出结果是:


=== RUN   TestObjLoop
9
9
9
9
9
9
9
9
9
9
--- PASS: TestObjLoop (0.00s)
PASS

正确的写法

// targetList的元素.Index 的输出结果: [0,1,2,3,4,5,6,7,8,9]
func TestObjLoop_1(t *testing.T) {
	var targetList []*Object // 指针类型的
	for loopCnt := 0; loopCnt < 10; loopCnt++ {
		var pObj *Object // 循环内新建对象,确保指针更新
		pObj = &Object{}
		pObj.Index = loopCnt
		targetList = append(targetList, pObj)
	}
	for _, obj := range targetList {
		fmt.Println(obj.Index)
	}
}

执行结果:

=== RUN   TestObjLoop_1
0
1
2
3
4
5
6
7
8
9
--- PASS: TestObjLoop_1 (0.00s)
PASS

case 3:

func TestObjLoop_2(t *testing.T) {
	var targetList []Object // 指针类型的
	var pObj Object
	pObj = Object{}
	for loopCnt := 0; loopCnt < 10; loopCnt++ {
		pObj.Index = loopCnt
		targetList = append(targetList, pObj)
	}
	for _, obj := range targetList {
		fmt.Println(obj.Index)
	}
}

实际执行结果:

=== RUN   TestObjLoop_2
0
1
2
3
4
5
6
7
8
9
--- PASS: TestObjLoop_2 (0.00s)
PASS

如果是 指针类型,要特别注意。

实际案例: 返回数组元素都是同一个指针,导致业务出错

在这里插入图片描述