range 关键字在 go 语言中是相当常用好用的语法糖,可以用在 for 循环中迭代 array、slice、map、channel、字符串所有涉及到遍历输出的东西。
基本原理
怎么用?
我们在前一节循环中初次触及到了 range,也知道他可以省略key,或者省略value来循环遍历的特性,但是这种特性要结合实际情况考量该用哪一个。
切片迭代
nums := []int{1, 2, 3} for k, v := range nums { fmt.Printf("key: %v , value: %v \n", k, v) }
这和迭代方式非常适合用for-range语句,如果减少赋值,直接索引num[key]可以减少损耗。如下
for k, _:= range nums {
map迭代注意,从 Go1开始,遍历的起始节点就是随机了。
kvs := map[string]string{ "a":"a", "b":"b", } for k, v := range kvs { fmt.Printf("key: %v , value: %v \n", k, v) }
函数中for-range语句中只获取 key 值,然后跟据 key 值获取 value 值,虽然看似减少了一次赋值,但通过 key 值查找 value 值的性能消耗可能高于赋值消耗。
所以能否优化取决于 map 所存储数据结构特征、结合实际情况进行。
字符串迭代(一个一个的输出字符)
for k,v := range "hello"{ //注意这里单个字符输出的是ASCII码, //用 %c 代表输出字符 fmt.Printf("key: %v , value: %c \n", k, v) }
channel (如果不会可以先 mark 下,详细参考后续:go 的并发特性章节)
ch := make(chan int, 10) ch <- 11 ch <- 12 close(ch) // 不用的时候记得关掉,不关掉又没有另一个goroutine存在会死锁哦,可以注释掉这一句体验死锁 for x := range ch { fmt.Println(x) }
结构体
tmp := []struct{ int string }{ {1, "a"}, {2, "b"}, } for k,v := range tmp{ fmt.Printf("k:%v, v:%v \n",k,v) }
注意:由于循环开始前循环次数就已经确定了,所以循环过程中新添加的元素是没办法遍历到的。
有可能会遇到的坑!
由于range遍历时value是值的拷贝,如果这个时候遍历上一节声明的结构体时,修改value,原结构体不会发生任何变化!
for _,v := range tmp{ v.a = 2 }
两次输出一致
k:0, v:{1 a} k:1, v:{2 b} k:0, v:{1 a} k:1, v:{2 b}
编程 Tips
- 遍历过程中可以适情况放弃接收 index 或 value,可以一定程度上提升性能
- 遍历 channel 时,如果 channel 中没有数据,可能会阻塞
- 尽量避免遍历过程中修改原数据
总结
- range可以用于for 循环中迭代 array、slice、map、channel、字符串所有涉及到遍历输出的东西。
- for-range 的实现实际上是C风格的for循环
- 使用index,value接收range返回值会发生一次数据拷贝
扫码二维码 获取免费视频学习资料
- 本文固定链接: http://phpxs.com/post/7379/
- 转载请注明:转载必须在正文中标注并保留原文链接
- 扫码: 扫上方二维码获取免费视频资料
查 看2022高级编程视频教程免费获取