funcmain() { sliceA := make([]int, 5) // 普通for循环 for i := 0; i < 5; i++ { sliceA[i] = i } }
golang中for的基本用法与Java中并无二致,这里不多赘述。
for&range
除了基本用法,golang中还提供了range关键字,进一步简化了遍历中取值的写法。
slice/数组的遍历
这里看看range在对slice/数组遍历中的几种用法:
1 2 3 4 5 6 7 8 9 10 11
funcmain() { sliceA := make([]int, 5) // for-range // i表示遍历的下标,v表示对应元素 for i := range sliceA { fmt.Printf("num1:%v,v:%v\n", i, sliceA[i]) } for i, v := range sliceA { fmt.Printf("num:%v,v:%v\n", i, v) } }
永动机
看到range的用法时,是否会想到,如果在遍历切片时不停的向其中塞数据,会变成一个永动机吗?
1 2 3 4 5
for i, v := range sliceA { sliceA = append(sliceA, i) fmt.Printf("yy:%v,v:%v\n", i, v) } fmt.Printf("sliceA:%+v\n", sliceA)
运行后会发现,上述代码并不会一直执行下去,循环次数取决于sliceA的初始长度。
这里可以看看源码range.go文件中的walkrange函数中的处理逻辑:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
// 这里是针对遍历切片的处理 case TARRAY, TSLICE: if arrayClear(n, v1, v2, a) { lineno = lno return n } // order.stmt arranged for a copy of the array/slice variable if needed. ha := a hv1 := temp(types.Types[TINT]) // 这里hn表示的是切片长度,这里初始化了,所以不会形成永动机 hn := temp(types.Types[TINT]) init = append(init, nod(OAS, hv1, nil)) init = append(init, nod(OAS, hn, nod(OLEN, ha, nil))) n.Left = nod(OLT, hv1, hn) n.Right = nod(OAS, hv1, nod(OADD, hv1, nodintconst(1)))
指针问题
1 2 3 4 5 6 7 8 9
funcmain() { sliceA := make([]int, 0) for i := 0; i < 9; i++ { sliceA = append(sliceA, i) } for _, v := range sliceA { fmt.Printf("value:%v\n", &v) } }