Go语言学习——三分钟看透iota
源起枚举
最近做需求时,有一个需要枚举的场景,大概有10+个枚举类型,不愿意像定义一个开关那样敷衍的写成
1 2 3 4 | const ( SwitchOff = 0 SwitchOn = 1 ) |
显得不够精致~
于是想到了iota,深入了解了下,这个小东西好像有点东西。
再回到需求本身——枚举。有了iota,就不用显示定义一大堆数值了。
未使用iota版本
1 2 3 4 5 6 7 8 9 | const ( ColorRed = 0 ColorOrange = 1 ColorYellow = 2 ColorGrassland = 3 ColorCyan = 4 ColorBlue = 5 ColorPurple = 6 ) |
使用iota版本
1 2 3 4 5 6 7 8 9 | const ( ColorRed = iota ColorOrange ColorYellow ColorGrassland ColorCyan ColorBlue ColorPurple ) |
两者的效果是一样的,各个枚举对应的值也是一样的。iota是从0开始,每一行都是往下递增。乍一看,iota还显得挺高端。
施展威力的同时,iota也有大家诟病的地方。
比如这时候如果需要添加一个"灰色"的枚举类型,在未使用iota版本里面不管在什么位置插入这个枚举,定义一个具体数值即可,比如对应7。
在使用iota版本里面如果加在ColorPurple后面,对应的值就是7,没有问题。
但是如果在其他位置,那就会打破原来的平衡,比如放在ColorGrassland后
1 2 3 4 5 6 7 8 9 10 | const ( ColorRed = iota // 0 ColorOrange // 1 ColorYellow // 2 ColorGrassland // 3 ColorGray // 4 ColorCyan // 5 ColorBlue // 6 ColorPurple // 7 ) |
可以看出,从加入ColorGray后,从ColorCyan开始以及后面的枚举对应的值都变了。如果各个枚举的值在代码中已经hard code了,那这样的调整将是灾难性的。
iota虽然灵活,但似乎有点过于灵活了。
看到这,你以为你已经了解了iota,不,你没有,它比你想的还要灵活、复杂。
iota的花式玩法
首先来看一道送分题
1 2 3 4 5 6 | const ( AA = iota BB _ DD ) |
问题
此时DD对应的值是多少?
稍稍推理下,显然不是2,因为中间还多了个下划线。
没错,DD对应的值是3。这里的下划线"_"表示跳过某值,原本对应在这个位置的值应该是2,但是获取它不重要,所以使用下划线跳过了,这个用法也和Go对应下划线的定义保持一致。
比如遍历map集合,不需要使用key值时,可以写成
1 2 3 | for _, value := range testMap { fmt.Println(value) } |
好,再看下一题
1 2 3 4 5 6 7 | const ( AA = iota BB _ DD = iota + 1 EE ) |
问题
此时DD和EE对应的值是多少?
与上例不同,这里在DD后面重新指定了DD = iota + 1,即在原有的数据上加1,所以此时DD的值为3+1=4。
后面EE没有重新定义,则也会顺延DD的规则递增1,即5。
如果上面一题你得到了正确的答案,那下面一题也不就不难了
1 2 3 4 5 6 7 8 | const ( AA = iota <br> BB _ DD = iota + 1 EE FF = iota + 2 GG = iota ) |
问题
此时FF和GG对应的值是多少。
根据上一题,DD和EE分别对应4和5。
首先看这里的FF,注意这里的FF并不是顺延EE的值加1,然后再加2,如果是顺延则FF = 6 + 2 = 8。但是FF的值是7。
每当某个枚举被重置(即后面使用iota重新赋值时),则需要从第一个枚举数到当前的次序,比如这里从AA=0数到FF,此时FF的次序是5,然后再加2,即FF=5+2=7。
GG的值使用上面的方法,得到值为6。
注意:以上是我从结果反推得到的结论,一开始难以理解这里各个枚举对应的值,找到这个规则后,发现程序跑出来值和规则验证的一样。
下面看最后一道题
1 2 3 4 | const ( AA, BB = iota + 1, iota + 2 CC, DD ) |
问题
此时的AA、BB、CC和DD对应的值分别是多少
这里只需要明白一个规则,iota是每行才会加一。
所以这里第一行的iota都是0,则AA和BB对应的值分别是0+1=1和0+2=2。
下面的CC和DD都是顺延,对应的iota递增则为1,然后分别按照iota+1和iota+2的运算得到值为1+1 = 2和1+2 = 3。
好了,做完上面不管是送分题还是送命题,我想,你对iota这个小东西算是有一个真正的了解。
个人感觉,功能实现千万条,看懂再用第一条。
回到枚举
有时候我们使用枚举,不仅是定义它的值,还需要有对应的描述信息,我们知道这在Java里面是比较方便实现的,毕竟Java本来就有枚举的概念。
下面我们看看Go实现带有描述信息枚举的两种方式。
使用map映射
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | const ( ColorRed = iota ColorOrange ColorYellow ColorGrassland ColorCyan ColorBlue ColorPurple ) var ColorMap = map [int]string{ ColorRed: "赤" , ColorOrange: "橙" , ColorYellow: "黄" , ColorGrassland: "绿" , ColorCyan: "青" , ColorBlue: "蓝" , ColorPurple: "紫" , } |
这样,如果想获取ColorRed对应的描述信息,就可以写成ColorMap[ColorRed]。
定义枚举类型
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | type Color int const ( ColorRed Color = iota ColorOrange ColorYellow ColorGrassland ColorCyan ColorBlue ColorPurple ) func (c Color) String() string { switch c { case ColorRed: return "赤" case ColorOrange: return "橙" case ColorYellow: return "黄" case ColorGrassland: return "绿" case ColorCyan: return "青" case ColorBlue: return "蓝" case ColorPurple: return "紫" } |
将颜色枚举定义为Color类型,则所有枚举值都是该类型,如果要获取ColorRed对应的描述信息,就可以写成ColorRed.String()。
这种方式看着更加优雅,也更有Go的味道~
如果您觉得阅读本文对您有帮助,请点一下“推荐”按钮,您的“推荐”将是我最大的写作动力!如果您想持续关注我的文章,请扫描二维码,关注JackieZheng的微信公众号,我会将我的文章推送给您,并和您一起分享我日常阅读过的优质文章。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架