经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 程序设计 » Go语言 » 查看文章
Go语言实现枚举的示例代码
来源:jb51  时间:2022/1/24 10:09:45  对本文有异议

在编程领域里,枚举用来表示只包含有限数量的固定值的类型,在开发中一般用于标识错误码或者状态机。拿一个实体对象的状态机来说,它通常与这个对象在数据库里对应记录的标识状态的字段值相对应。

在刚开始学编程的时候,你一定写过,至少见过直接使用魔术数字进行判断的代码。啥叫魔术数字呢,举个例子,要置顶一个文章的时候先判断文章是不是已发布状态。

  1. if (article.state == 2) {
  2. ? ?// state 2 代表文章已发布
  3. }

假如我们的代码里没有注释,或者等我们项目的代码里充斥着这些魔术数字的判断的时候,你是不是会很头疼?
后来我就学会了把这些状态值定义成常量,并且也搞一个判断对象状态的方法单独封装这段逻辑。

  1. public class ArticleState {
  2. ? ??
  3. ? ? public static final int Draft = 1; //草稿
  4. ? ??
  5. ? ? public static final int Published = 2; //发布
  6. ? ??
  7. ? ? public static final int Deleted = 3; // 已删除
  8. }
  9.  
  10. public ?Boolean checkArticleState(int state) {
  11. ? ??
  12. ? ? ...
  13. ? ??
  14. }

这种用法,肯定是比在程序里直接用魔术数字进行判断要强很多啦,至少看着不会很头疼,不会想骂**。

不过后来被当时带我的老大哥说这种也有缺点,上面这个 checkArticleState 方法用来检查文章状态,本意是让调用者传入 ArticleState 的三个静态常量之一,但由于没有类型上的约束,因此传入任意一个 int 值在语法上也是允许的,编译器也不会提出任何警告,用枚举更合适一些。
em~! 我不记得大学教 Java 的那个学期老师讲过这玩意啊,莫非又是一个上课玩手机错过的知识点?所以使用枚举后我们的Java代码变成了:

  1. // 使用enum而非class声明
  2. public enum ArticleState {
  3. ?? ?
  4. ? ? //要在enum里创建所有的枚举对象
  5. ? ? Draft(1, "草稿");
  6. ? ? Published(2, "已发布");
  7. ? ? Deleted(3, "已删除")
  8. ? ? ??
  9. ? ? // 自定义属性
  10. ? ? private int code;
  11.  
  12. ? ? private String text;
  13. ??
  14. ? ? // 构造方法必须是private的
  15. ? ? ArticleState(int code, String text) {
  16. ? ? ? ? this.code = id;
  17. ? ? ? ? this.text = name;
  18. ? ? }
  19. }
  20.  
  21. public ?Boolean checkArticleState(ArticleState state) {
  22. ? ??
  23. ? ? ...
  24. ? ??
  25. }

这样就能靠形参的枚举类型帮我们过滤掉非法的状态值,把整型值作为参数传给 checkArticleState 方法时因为类型不匹配编译不过去,在写代码是编译器也能马上提示出来。

如果没有用过 Java 的小伙伴也不用纠结,主要语法点我用注释标注出来了,大家应该都能看懂。后来这两年主要在用Go做项目,我发现相似的问题 Go 里存在,但是 Go 并没有提供枚举类型,那怎么做到进行状态值的正确限制呢?如果还是用 int 型的常量肯定不行。比如:

  1. ?const (
  2. ? ? ?Draft int = 1
  3. ? ? ?Published = 2
  4. ? ? ?Deleted ? = 3
  5. ?)
  6.  
  7. ?const (
  8. ? ? ?Summer int = 1
  9. ? ? ?Autumn ? ? = 2
  10. ? ? ?Winter ? ? = 3
  11. ? ? ?Spring ? ? = 4
  12. ?)
  13.  
  14. ?func main() {
  15. ? ? ?// 输出 true, 不会有任何编译错误
  16. ? ? ?fmt.Println(Autumn == Draft)
  17. ?}

比如上面定义了两组 int 类型的常量,一类代表文章状态,一类代表季节的四季。这种方式拿文章状态与季节进行比较不会有任何编译上的错误。

答案在 Go 内置库或者一些咱们都知道的开源库的代码里就能找到。比如看看 google.golang.org/grpc/codes 里的gRPC 的错误码是怎么定义的,就能明白该怎么正确的实现枚举。

我们可以用 int 作为基础

  1. type Season int
  2.  
  3. const (
  4. ?? ?Summer Season = 1
  5. ?? ?Autumn ? ? ? ?= 2
  6. ?? ?Winter ? ? ? ?= 3
  7. ?? ?Spring ? ? ? ?= 4
  8. )

类型创建一个别名类型,Go 里边是支持这个的

当然定义连续的常量值的时候 Go 里边经常使用 iota,所以上面的定义还能进一步简化。

  1. type Season int
  2.  
  3. const (
  4. ?? ?Summer Season = iota + 1
  5. ?? ?Autumn
  6. ?? ?Winter
  7. ?? ?Spring
  8. )
  9.  
  10. type ArticleState int
  11.  
  12. const (
  13. ? Draft int = iota + 1
  14. ? Published
  15. ? Deleted ?
  16. )
  17.  
  18. func checkArticleState(state ArticleState) bool {
  19. ?? ?// ...?
  20. }
  21.  
  22. ?func main() {
  23. ? ?// 两个操作数类型不匹配,编译错误
  24. ? ?fmt.Println(Autumn == Draft)
  25. ?? ?// 参数类型不匹配,但是因为 ArticleState 底层的类型是 int 所以传递 int 的时候会发生隐式类型转换,所以不会报错
  26. ? ?checkArticleState(100)
  27. ?}

虽然这些状态值的底层的类型都是 int 值,但是现在进行两个不相干类型的枚举值比较,会造成编译错误,因为现在我们使用状态值的地方都有了类型限制。
不过函数 checkArticleState 的参数类型设置成了 ArticleState 但是因为 ArticleState 底层的类型是 int 。所以调用 checkArticleState  时传递 int 类型的参数会发生隐式类型转换,不会造成编译报错,这块如果想解决,只能重新定义类型来实现了,可以参考StackOverflow上的这个答案

到此这篇关于Go语言实现枚举的示例代码的文章就介绍到这了,更多相关Go语言 枚举内容请搜索w3xue以前的文章或继续浏览下面的相关文章希望大家以后多多支持w3xue!

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号