侧边栏壁纸
博主头像
SeaDream乄造梦

Dream,Don't stop a day of hard and don't give up a little hope。 ——不停止一日努力&&不放弃一点希望。

  • 累计撰写 63 篇文章
  • 累计创建 21 个标签
  • 累计收到 14 条评论

目 录CONTENT

文章目录

go 关键字 range

SeaDream乄造梦
2024-12-10 / 0 评论 / 0 点赞 / 54 阅读 / 1,706 字
温馨提示:
亲爱的,如果觉得博主很有趣就留下你的足迹,并收藏下链接在走叭

实现原理

1. // Arrange to do a loop appropriate for the type. We will produce 
2. // for INIT ; COND ; POST { 
3. // ITER_INIT 
4. // INDEX = INDEX_TEMP 
5. // VALUE = VALUE_TEMP // If there is a value 
6. // original statements 
7. // }

可见range实际上是一个C风格的循环结构。range支持数组、数组指针、切片、map和channel类型,对于不同类型有些细节上的差异。

请看题


/*
下面函数通过遍历切片,打印切片的下标和元素值,请问性能上有没有可优化的空间?
答:遍历过程中每次迭代会对index和value进行赋值,如果数据量大或者value类型为string时,对value的赋值操作可能是多余的,可以在for-range中忽略value值,使用slice[index]引用value值。
*/
func RangeSlice(slice []int) {
	for index, value := range slice {
		_, _ = index, value
	}
}

/* 下面函数通过遍历Map,打印Map的key和value,请问性能上有没有可优化的空间?
答:函数中for-range语句中只获取key值,然后跟据key值获取value值,虽然看似减少了一次赋值,但通过key值查找value值的性能消耗可能高于赋值消耗。能否优化取决于map所存储数据结构特征、结合实际情况进行。
*/

func RangeMap(myMap map[int]string) {
	for key, _ := range myMap {
		_, _ = key, myMap[key]
	}
}

/*
请问如下程序是否能正常结束?
答:能够正常结束。循环内改变切片的长度,不影响循环次数,循环次效在循环开始前就已经确定了。
*/
func TestRange(t *testing.T) {
	v := []int{1, 2, 3}
	for i := range v {
		v = append(v, i)
	}
}


3.2 range for slice

1. // The loop we generate: 
2. // for_temp := range 
3. // len_temp := len(for_temp) 
4. // for index_temp = 0; index_temp < len_temp; index_temp++ { 
5. // value_temp = for_temp[index_temp] 
6. // index = index_temp 
7. // value = value_temp 
8. // original body 
9. // }

遍历slice前会先获以slice的长度len_temp作为循环次数,循环体中,每次循环会先获取元素值,如果for-range中接收index和value的话,则会对index和value进行一次赋值。
由于循环开始前循环次数就已经确定了,所以循环过程中新添加的元素是没办法遍历到的。

3.3 range for map

1. // The loop we generate: 
2. // for { 
3. // index_temp, ok_temp = <-range 
4. // if !ok_temp { 
5. // break 
6. // } 
7. // index = index_temp 
8. // original body 
9. // }

channel遍历是依次从channel中读取数据,读取前是不知道里面有多少个元素的。如果channel中没有元素,则会阻塞等待,如果channel已被关闭,则会解除阻塞并退出循环。

  • 上述注释中index_temp实际上描述是有误的,应该为value_temp,因为index对于channel是没有意义的。
  • 使用for-range遍历channel时只能获取一个返回值。

3.5 编程Tips

  • 遍历过程中可以看况放弃接收index或value,可以一定程度上提升性能
  • 遍历channel时,如果channel中没有数据,可能会阻塞
  • 尽量避免遍历过程中修改原数据

3.6 总结

  • for-range的实现实际上是C风格的for循环
  • 使用index,value接收range返回值会发生一次数据拷贝
0

评论区