Go语言学习——三分钟看透iota

源起枚举

最近做需求时,有一个需要枚举的场景,大概有10+个枚举类型,不愿意像定义一个开关那样敷衍的写成

const (
    SwitchOff = 0
    SwitchOn  = 1
)

显得不够精致~

于是想到了iota,深入了解了下,这个小东西好像有点东西。

再回到需求本身——枚举。有了iota,就不用显示定义一大堆数值了。

未使用iota版本

const (
  ColorRed         = 0
  ColorOrange 		= 1
  ColorYellow 		= 2
  ColorGrassland 	= 3
  ColorCyan 		= 4
  ColorBlue 		= 5
  ColorPurple 		= 6
)

  

使用iota版本

const (
  ColorRed 		= iota
  ColorOrange
  ColorYellow
  ColorGrassland
  ColorCyan
  ColorBlue
  ColorPurple
)

 

两者的效果是一样的,各个枚举对应的值也是一样的。iota是从0开始,每一行都是往下递增。乍一看,iota还显得挺高端。

施展威力的同时,iota也有大家诟病的地方。

比如这时候如果需要添加一个"灰色"的枚举类型,在未使用iota版本里面不管在什么位置插入这个枚举,定义一个具体数值即可,比如对应7。

使用iota版本里面如果加在ColorPurple后面,对应的值就是7,没有问题。

但是如果在其他位置,那就会打破原来的平衡,比如放在ColorGrassland后

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的花式玩法

首先来看一道送分题

const (
	AA = iota
	BB
	_
	DD
)

  

问题

此时DD对应的值是多少?

稍稍推理下,显然不是2,因为中间还多了个下划线。

没错,DD对应的值是3。这里的下划线"_"表示跳过某值,原本对应在这个位置的值应该是2,但是获取它不重要,所以使用下划线跳过了,这个用法也和Go对应下划线的定义保持一致。

比如遍历map集合,不需要使用key值时,可以写成

for _, value := range testMap {
  fmt.Println(value)
}

  

好,再看下一题

const (
	AA = iota
	BB
	_
	DD = iota + 1
	EE
)

  

问题

此时DD和EE对应的值是多少?

与上例不同,这里在DD后面重新指定了DD = iota + 1,即在原有的数据上加1,所以此时DD的值为3+1=4。

后面EE没有重新定义,则也会顺延DD的规则递增1,即5。

如果上面一题你得到了正确的答案,那下面一题也不就不难了

const (
  AA = iota   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。

注意:以上是我从结果反推得到的结论,一开始难以理解这里各个枚举对应的值,找到这个规则后,发现程序跑出来值和规则验证的一样。

下面看最后一道题

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映射

const (
	ColorRed 				= iota
      ColorOrange
      ColorYellow
      ColorGrassland
      ColorCyan
      ColorBlue
      ColorPurple
)

var ColorMap = map[int]string{
	ColorRed:       "赤",
	ColorOrange:    "橙",
	ColorYellow:    "黄",
	ColorGrassland: "绿",
	ColorCyan:      "青",
	ColorBlue:      "蓝",
	ColorPurple:    "紫",
}

  

这样,如果想获取ColorRed对应的描述信息,就可以写成ColorMap[ColorRed]。

定义枚举类型

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的微信公众号,我会将我的文章推送给您,并和您一起分享我日常阅读过的优质文章。

原文地址:https://www.cnblogs.com/bigdataZJ/p/go-iota.html

时间: 2024-08-01 13:06:00

Go语言学习——三分钟看透iota的相关文章

Dart语言学习( 三) Dart数值型

一.类型 数值型有 num,int, double  num a = 10; a = 12.5; print(a); print(a.runtimeType); int b = 20; // b = 20.5; print(b); print(b.runtimeType); double c = 10.5; // c = 30; print(c); print(c.runtimeType); print("\n"); 其中,runtimeType 为运行时的类型. 输出如下: 12.5

OC语言学习 (三) 成员变量get/set方法和“.”语法,@proterty和@synthesize关键字

Person.h #ifndef oc_Person_h #define oc_Person_h @interface Person : NSObject { int age; @protected float height; } - (int) age; //get方法 - (void) setAge:(int)pAge; //set方法 @end #endif Person.m #import <Foundation/Foundation.h> #import "Person.h

用三分钟理解c语言sizeof

一.概念 sizeof是单目操作符,同++等操作符一样.作用是以字节形式输出操作对象所在储存大小. 二.用法 a.操作数据类型 如sizeof(int),输出int类型在内存中所占的字节长度,具体取决于具体环境,本机输出为4. b.操作变量 如 char a[6]; printf("%d\n" ,sizeof(a)),因为已经定义了char数组长度,所以输出值为6. 三.常见问题 有以下几个例子,需要引起注意: 例子1: int testSizeOf(char x[]) { retur

JavaScript--基于对象的脚本语言学习笔记(三)

事件处理器 1.一个数据校验表单的例程 <html> <head> <title>js练习</title> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> <script type="text/javascript"> String.prototype.trim=function(){ r

iOS学习笔记---oc语言第三天

继承.初始化方法 一.继承 继承的上层:父类  继承的下层:子类 继承是单向的,不能相互继承 继承具有传递性:A继承于B,B继承于C,A具有B和C的特征和行为 子类能继承父类全部的特征和行为(私有变量也继承过来了,只是不能访问) 面向对象提供了继承语法.能大大简化代码,把公共的方法和实例对象写在父类里.子类只需要写自己独有的实例变量和方法即可 继承既能保证类的完整,又能简化代码 继承特点 oc中只允许单继承 没有父类的类称为根类,oc中得根类是NSObject(祖宗) 继承的内容:所有的实例变量

C语言学习笔记(三) 输入输出函数的基本用法以及运算符

printf() ——将内容输出到显示器上 四种用法 1.printf("字符串");   直接输出字符串 2.printf("输出控制符",输出参数); 3.printf("输出控制符1 输出控制符2",输出参数1,输出参数2); 输出控制符和输出参数的个数必须一致: 4.printf("输出控制符 非输出控制符",输出参数); 输出控制符包含如下: 1.%d —— int 2.%ld ——  long int 3.%c —

Go语言学习笔记(三) [控制结构、内建函数]

日期:2014年7月21日 一.控制结构 1.Go中,只有几个控制结构,它没有do或者while循环,有for,灵活的switch语句和if,在switch中可以接受像for那样可选的初始化语句,另外Go中还提供了类型选择和多路通信转接器的select.Go的控制结构的语法和C相比有所不同,它不需要圆括号,但语句体必须总是包含在大括号内. 2.控制结构语法 1)if-else (1)if后紧跟单个条件 例如:if x > 0 {   //{必须和if在同一行,这是Go语法规定的,如果换行写,编译

C++语言学习(三)——封装(Encapsulation)

C++语言学习(三)--封装(Encapsulation) 一.封装简介 C语言等面向过程编程中,数据以及数据的相关操作函数都是分离的独立个体:在C++等面向对象编程中,数据以及数据的相关操作被设计为对象,对象包括属性(数据)和操作(函数),两者共同构成对象实体(即类实体).面向对象编程使程序更模块化,更易读易写,提升了代码重用到一个更高的层次.面向对象编程中,数据和数据的操作封装为了对象.封装可以隐藏实现细节,使得代码模块化,是把过程和数据包围起来,对数据的访问只能通过已定义的接口.封装是一种

三分钟看懂上证50ETF期权,基础学习

三分钟看懂上证50ETF期权,基础学习 最近50RETF期权投资,广受投资者朋友的欢迎,但也有一些朋友对此不是非常了解,今天 optioncc期权小编 我们就来给大家介绍一下50ETF期权! 首先我们先来了解一下什么是50ETF期权? 50ETF期权是经过上海证券交易所的三个衍生产品,从上证50指数到50ETF指数基金再到50ETF期权,我们先来了解一下上证50指数. 他是由上海证券交易所编制的,是从众多股票中选择了最具代表性的50只股票,像中国平安.民生银行.伊利股份.贵州茅台等,而他们的行情