文章目录
range是go提供的一种迭代遍历手段。
range遍历
range遍历可操作的类型有数组(包括字符串)、切片、Map、channel等:
- index、value接收range返回值会发生一次数据拷贝;根据情况放弃接收index或value(使用
_
),可一定程度上提升性能; - 对于channel,没有数据时,会被阻塞;
- 尽量避免遍历过程中修改原数据;
遍历slice
遍历slice前,会先获取其长度作为循环次数;循环体中,每次循环会先获取元素值,若需要index与value的话,则进行赋值;
遍历切片的伪码:
// for_temp := range-slice
// len_temp := len(for_temp)
// for index_temp = 0; index_temp < len_temp; index_temp++ {
// value_temp = for_temp[index_temp]
// index = index_temp
// value = value_temp
// original body
// }
循环开始前循环次数就已经确定了, 所以循环过程中新添加的元素是不会被遍历到的。
遍历数组、切片时,对value的修改不会影响数组、切片中的原有数据;要修改原来的数据,需要使用下标(ary[index]
)。
遍历数组、切片时,返回(index, value):
nums := []int{2, 3, 4}
sum := 0
for _, num := range nums {
sum += num
}
遍历map
map底层使用hash表实现,插入数据位置是随机的,所以遍历过程中新插入的数据不能保证遍历到(可能会被遍历到,也可能遍历不到)。
遍历map的伪码:
// var hiter map_iteration_struct
// for mapiterinit(type, range, &hiter); hiter.key != nil; mapiternext(&hiter) {
// key_temp = *hiter.key
// value_temp = *hiter.val
// key = key_temp
// value = value_temp
// original body
// }
遍历map时,返回(key,value):
fruits := map[string]string{"a": "apple", "b": "banana"}
for k, v := range fruits {
fmt.Printf("%s -> %s\n", k, v)
}
遍历channel
channel是依次从通道中读取数据:
- 如果通道中没有元素,则会阻塞等待;
- 如果channel已被关闭,则会解除阻塞并退出循环;
遍历通道伪码:
// for {
// value_temp, ok_temp = <-range
// if !ok_temp {
// break
// }
// value = value_temp
// original body
// }
遍历channel时,返回接收到的数据:
ch := make(chan int)
// 发送数据的goroutine
go func() {
for i := 0; i < 5; i++ {
ch <- i+1 //往通道写数据
}
//不需要再写数据时,关闭channel
close(ch)
}()
for num := range ch {
fmt.Println("num = ", num)
}