go底层系列-range原理剖析

本文深入探讨了Go语言中的for-range迭代机制,包括对数组、切片、Map和channel的遍历。讲解了for-range的实现原理,强调了遍历过程中的性能优化和注意事项,如避免不必要的赋值操作,并指出在遍历channel时可能存在的阻塞问题。此外,还提供了编程Tips,建议根据实际情况选择是否接收index或value,以及避免在遍历过程中修改原数据。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

range

前言

  • range是Golang提供的一种迭代遍历手段

  • 可操作的类型有数组、切片、Map、channel

  • 实际使用频率非常高

热身

func RangeSlice(slice []int) {
	for index, value := range slice {
		_, _ = index, value
	}
}
// 程序解释:函数中使用for-range对切片进行遍历,获取切片的下标和元素素值
// 参考答案:
//		遍历过程中每次迭代会对index和value进行赋值
//		如果数据量大或者value类型为string时,对value的赋值操作可能是多余的,
//		可以在for-range中忽略value值,使用slice[index]引用value值



// Map遍历
func RangeMap(myMap map[int]string) {
	for key, _ := range myMap {
		_, _ = key, myMap[key]
	}
}
// 参考答案:
// 		函数中for-range语句中只获取key值,然后跟据key值获取value值,虽然看似减少了一次赋值
// 		但通过key值查找value值的性能消耗可能高于赋值消耗。
//		能否优化取决于map所存储数据结构特征、结合实际情况进行



// 动态遍历
func main() {
	v := []int{1, 2, 3}
	for i := range v {
		v = append(v, i)
	}
}
// 程序解释:
//		main()函数中定义一个切片v,通过range遍历v,遍历过程中不断向v中添加新的元素。
// 参考答案:
//		能够正常结束。循环内改变切片的长度,不影响循环次数,循环次效在循环开始前就已经确定了。

实现原理

  • 可以从编译器源码中找到答案

    • 编译器源码 gofrontend/go/statements.cc/For_range_statement::do_lower() 方法中有如下注释
      在这里插入图片描述
  • 可见range实际上是一个C风格的循环结构

    • range支持数组、数组指针、切片、map和channel类型
    • 对于不同类型 有些细节上的差异

range for slice

下面的注释解释了遍历slice的过程:

在这里插入图片描述

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

range for array

数组与数组指针的遍历过程与slice基本一致,不再赘述


range for map

下面的注释解释了遍历map的过程:

在这里插入图片描述

  • 遍历map时没有指定循环次数
  • 循环体与遍历slice类似
  • 由于map底层实现与slice不同
    • map底层使用hash表实现,插入数据位置是随机的
      • 所以遍历过程中新插入的数据不能保证遍历到

range for channel

遍历channel是最特殊的,这是由channel的实现机制决定的:

在这里插入图片描述

  • 依次从channel中读取数据,读取前是不知道里面有多少个元素的。

    • 如果channel中没有元素,则会阻塞等待,
    • 如果channel已被关闭,则会解除阻塞并退出循环
  • 注:

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

编程Tips

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

总结

  • for-range的实现实际上是C风格的for循环
  • 使用index,value接收range返回值
    • 会发生一次数据拷贝
蓝牙4.0BLE(低耗蓝牙)完全开发手册是一本详细介绍蓝牙4.0BLE技术以及其开发的书籍。该手册提供了全面的信息,帮助开发者理解和运用蓝牙4.0BLE技术。 在蓝牙4.0BLE完全开发手册中,首先会对蓝牙技术做简要介绍,包括其发展历史、应用领域和主要特点。接下来会详细讲解蓝牙4.0BLE的原理和架构,以及与传统蓝牙的区别和优势。 然后,手册会深入介绍蓝牙4.0BLE的开发过程。首先是硬件方面,讲解了蓝牙4.0BLE芯片的选择和使用,以及与其他硬件模块的接口和连接。 接着,手册会详细介绍蓝牙4.0BLE的软件开发。从蓝牙协议栈的架构和功能开始,包括扫描、连接、传输和配置等。随后,会讲解关于蓝牙4.0BLE的数据传输和安全性的技术细节,如数据格式、特征值和服务的定义等。 在软件开发的过程中,手册还会介绍一些常见的开发工具和开发环境,包括蓝牙4.0BLE开发板、调试工具和开发软件的配置和操作。 最后,手册还会提供一些实际案例和应用示例,以便开发者更好地理解和运用蓝牙4.0BLE技术。同时,手册也会介绍一些开发中的常见问题和解决方法,以及软件和硬件的调试技巧和注意事项。 总之,蓝牙4.0BLE完全开发手册是一本全面而实用的参考书,适合对蓝牙4.0BLE技术感兴趣的开发者和工程师,能够帮助他们深入理解蓝牙4.0BLE技术,掌握开发过程中的关键技术和实践经验。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值