三分钟学 Go 语言——range深度解析

小熊最近两天加班比较严重,要处理的事情很多,但是学习的热情永远不会减少,前面讲述的go语言语法是非常非常简单的,所以没有做深入的剖析,后面会从各种角度解析语法,fighting!!

range(范围)

range 关键字在 go 语言中是相当常用好用的语法糖,可以用在 for 循环中迭代 arrayslicemapchannel字符串所有涉及到遍历输出的东西。

基本原理
怎么用?

我们在前一节循环中初次触及到了 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
  • 遍历过程中可以适情况放弃接收 indexvalue,可以一定程度上提升性能
  • 遍历 channel 时,如果 channel 中没有数据,可能会阻塞
  • 尽量避免遍历过程中修改原数据
总结
  • range可以用于for 循环中迭代 arrayslicemapchannel字符串所有涉及到遍历输出的东西。
  • for-range 的实现实际上是C风格的for循环
  • 使用index,value接收range返回值会发生一次数据拷贝
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

机智的程序员小熊

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值