range用来遍历 数组、slice、map、channel,使用非常频繁
一:可优化的地方
func RangeSlice(slice []int) {
for index, value := range slice {
_, _ = index, value
}
}
func RangeMap(myMap map[int]string) {
for key, _ := range myMap {
_, _ = key, myMap[key]
}
}
for range的时候,index和value都是copy的一份,所以在range的过程中,copy可能影响性能,可能存在可以优化的地方。比如遍历slice的时候,value都是复制来复制去,不妨试试直接把value省略,采用slice[index]来访问value,但是如果是遍历map,采用省略value的形式 并一定高效,因为通过key再去map中获取值 又是一个繁琐的操作。所以说for range的时候 到底要不要value,具体情况具体再说。
二:实现原理
// Arrange to do a loop appropriate for the type. We will produce
// for INIT ; COND ; POST {
// ITER_INIT
// INDEX = INDEX_TEMP
// VALUE = VALUE_TEMP // If there is a value
// original statements
// }
golang中range,最终转化的大致形式 是类似c or c++中的三段式for,只是对于数组、slice、map、channel 不同的类型 有不同的细微差别。
2.1:遍历数组、slice
以数组、slice的长度 作为循环次数,循环开始前遍历次数都已经确定了,所以循环过程中新加入元素不会被遍历到也不会导致循环无休止。
2.2:遍历map
并没有循环次数,因为从map中的keys()存储在一个链表中,遍历链表就没有必要指定循环次数了。获取到的keys()是一个乱序的,所以在循环中插入元素,新插入的元素可能遍历不到也可能后边可以遍历的到,这个问题前边有文章说明。
2.3:遍历channel
遍历channel跟前边的有点区别,因为读取前不知道channel中有多少元素,可能有也可能没有,如果没有元素则会阻塞等待,如果channel被关闭则会解除阻塞并退出循环。还有一个区别就是遍历channel,只有value的概念 没有index的概念。