Go 真的有枚举吗?
发布日期:2022-02-01 16:54:05 浏览次数:23 分类:技术文章

本文共 2375 字,大约阅读时间需要 7 分钟。

Go 中有枚举吗?这是一个模棱两可的问题。有人说它有,有人说它没有。

什么是枚举

代码抽象于现实。程序与生活中关于枚举的概念是相通的:枚举代表一个对象所有可能取值的集合。例如,表示星期的 SUNDAY、MONDAY、TUESDAY、WEDNESDAY、THURSDAY、FRIDAY、SATURDAY 就是一组枚举值。

实际上,我们可以将 Go 中所有原始类型视为一种枚举。例如 bool 类型可以被认为是一个只能为 true 或 false 的枚举;byte 类型是 0 至 255 的枚举;指针是 32 位或 64 位地址空间所有可能的内存地址的枚举。

在例如 Python、Java、C 等语言中,一般都会有enum关键字或类提供于开发者实现枚举。

通用伪代码可表达如下

enum 枚举名{    标识符①[=整型常数],    标识符②[=整型常数],    ...    标识符N[=整型常数],}枚举变量;

Go 没有enum关键字。但我们可以观察枚举的特征:同一组枚举值在定义后不应被改变;枚举值对应的数据类型应该相同;枚举值是有限的;枚举值与其含义是一一对应的。

根据以上特征,在 Go 中可通过const与  iota关键字来实现枚举的诉求。

iota

const用于定义常量,它们在编译期创建,在运行时不能被修改。且仅有布尔型、数字型(整数型、浮点型和复数)和字符串型能被定义为常量。

常量声明格式如下

const identifier [type] = value

而 iota 是常量计数器,它在遇到 const 关键字时,就被重置为 0。当 const 中每增一行常量声明(包括空白标识符_),iota 计数将加1。

const ( A int = iota   // 0 _            B              // 2 C              // 3 D              // 4)const ( E int = iota   // 0 F              // 1)

Go 枚举实现

有了iota的参与,在 Go 中想要枚举星期值,我们可以如下定义

type Weekday intconst ( _ Weekday = iota // ignore first value by assigning to blank identifier Sunday Monday Tuesday Wednesday Thursday Friday Saturday)

在使用枚举值过程中,往往有输出打印的需求

fmt.Println(Sunday, Monday)  // 1 2

但原始的结果很不直观,它不能反映出枚举值背后的含义。我们需要为 Weekday 对象定义输出。

func (w Weekday) String() string { return [...]string{"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"}[w-1]}

在 Go 中,我们可以为任意自定义类型绑定String()方法,使其按照String()方法中定义的格式进行打印。

func main() { var day = Monday switch day { case Monday, Tuesday, Wednesday, Thursday, Friday:  fmt.Printf("今天是%s,加油!打工人", day) case Saturday, Sunday:  fmt.Printf("今天是%s,好好休息!打工人", day) default:  fmt.Println("不存在的一天") }}

执行结果

今天是Monday,加油!打工人

Go 枚举实现的不足

上述方案看似已经实现了枚举功能,但其实存在一些问题。

首先,由于 iota 基于 int 类型,这意味着在程序中,任何整数都可以转为枚举类型(这也是为何我们上文switchcase 中会有default分支),但这并不是我们想要的。

func main() { fakeNum := 8 day := Weekday(fakeNum) fmt.Println(day)}# go run main.go%!v(PANIC=String method: runtime error: index out of range [7] with length 7)

那善于思考的读者就会想到,既然 int 不行,那我们可以采用字符串常量来表示枚举值啊。但这个方案同样存在上述的问题,而且相较于使用 int 比较,当比较字符串时,需要付出额外的性能成本。

另外,我们对于枚举还有一个很重要的诉求,就是迭代。对应于 Go 循环表达式,枚举迭代的期望是这样

for i, day := range Weekday {  ... }

但显然,现在的代码方案满足不了这种诉求。

总结

本文讨论了 Go 目前通过 iota 关键字实现枚举的做法,但这种方式并没有实现完整的枚举功能。在官方 issue 19814 中提出了 Go 中应该增加 enum 关键字的提案,感兴趣的读者可以详细查看。

关于 Go 中的枚举实现,你有不一样的观点吗,欢迎留言讨论。

参考

proposal: spec: add typed enum support: https://github.com/golang/go/issues/19814

往期推荐

cf312201d725a65237cc08f76c028888.png

机器铃砍菜刀

欢迎添加小菜刀微信

加入Golang分享群学习交流!

感谢你的点赞在看哦~

13cf08b6efe4ca9c199279b125cd479b.gif

转载地址:https://blog.csdn.net/slphahaha/article/details/121623614 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:在你的 Android 手机上运行 Golang 程序
下一篇:应该如何去选择 Go router?

发表评论

最新留言

表示我来过!
[***.240.166.169]2024年03月17日 12时13分52秒

关于作者

    喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!

推荐文章

fei 正则表达式_java 学习笔记之正则表达式 2019-04-21
mysql事务与redis事务_Mysql与Redis事务 2019-04-21
unix下ODBC连接MySQL编程_unixodbc|unixodbc(连接数据库组件)下载v2.3.7 官方版 - 欧普软件下载... 2019-04-21
java sdk_Java SDK的下载、安装和环境配置 2019-04-21
常量与变量 java_详解Java变量与常量 2019-04-21
java布局代码_JAVA布局管理器与面板组合代码实例 2019-04-21
java工程导出jar_Eclipse将java项目导出可执行的jar文件 2019-04-21
java 集合join_Java中的join方法实现(支持集合或map) 2019-04-21
java8Lambda 表达式_Java8学习笔记(一)--Lambda表达式 2019-04-21
java版本号49.0_又是48,49JDK版本不兼容(Unsupported major.minor version 49.0) | 学步园... 2019-04-21
java servlet文件下载_Java Servlet实现下载文件 2019-04-21
java 负载均衡 算法_几种简单的负载均衡算法及其Java代码实现 2019-04-21
java用date定义报错_Java定义一个日期Date类出错,请问Java大神是什么原因? 2019-04-21
python cnn入门_神经网络学习之Ndarray对象和CNN入门 2019-04-21
java总线_用RxJava实现事件总线(Event Bus) 2019-04-21
java xml dom解析xml_Java DOM解析器 - 解析XML文档 2019-04-21
java编码解析解析_java如何解析如下的字符串编码? 2019-04-21
java byte转int原理_java中int与byte数组互转代码详细分析 2019-04-21
java list keystore_Java / Keystore验证签名证书 2019-04-21
java中的错误流_关于java中流关闭的问题 2019-04-21