Go语言实现枚举的示例代码

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

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

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

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

public class ArticleState {
    
    public static final int Draft = 1; //草稿
    
    public static final int Published = 2; //发布
    
    public static final int Deleted = 3; // 已删除
}

public  Boolean checkArticleState(int state) {
    
    ...
    
}

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

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

// 使用enum而非class声明
public enum ArticleState {
    
    //要在enum里创建所有的枚举对象
    Draft(1, "草稿");
    Published(2, "已发布");
    Deleted(3, "已删除")
      
    // 自定义属性
    private int code;

    private String text;
  
    // 构造方法必须是private的
    ArticleState(int code, String text) {
        this.code = id;
        this.text = name;
    }
}

public  Boolean checkArticleState(ArticleState state) {
    
    ...
    
}

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

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

 const (
     Draft int = 1
     Published = 2
     Deleted   = 3
 )

 const (
     Summer int = 1
     Autumn     = 2
     Winter     = 3
     Spring     = 4
 )

 func main() {
     // 输出 true, 不会有任何编译错误
     fmt.Println(Autumn == Draft)
 }

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

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

我们可以用 int 作为基础

type Season int

const (
    Summer Season = 1
    Autumn        = 2
    Winter        = 3
    Spring        = 4
)

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

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

type Season int

const (
    Summer Season = iota + 1
    Autumn
    Winter
    Spring
)

type ArticleState int

const (
  Draft int = iota + 1
  Published
  Deleted  
)

func checkArticleState(state ArticleState) bool {
    // ... 
}

 func main() {
   // 两个操作数类型不匹配,编译错误
   fmt.Println(Autumn == Draft)
    // 参数类型不匹配,但是因为 ArticleState 底层的类型是 int 所以传递 int 的时候会发生隐式类型转换,所以不会报错
   checkArticleState(100)
 }

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

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

(0)

相关推荐

  • Go语言基础枚举的用法及示例详解

    目录 概述 一.普通枚举 二.自增枚举 注意 代码 概述 将变量的值一一列举出来,变量只限于列举出来的值的范围内取值 Go语言中没有枚举这种数据类型的,但是可以使用const配合iota模式来实现 一.普通枚举 const ( cpp = 0 java = 1 python = 2 golang = 3 ) 二.自增枚举 iota只能在常量的表达式中使用 fmt.Println(iota) //undefined: iota 它默认开始值是0,const中每增加一行加1 const ( a =

  • Go语言实现枚举的示例代码

    在编程领域里,枚举用来表示只包含有限数量的固定值的类型,在开发中一般用于标识错误码或者状态机.拿一个实体对象的状态机来说,它通常与这个对象在数据库里对应记录的标识状态的字段值相对应. 在刚开始学编程的时候,你一定写过,至少见过直接使用魔术数字进行判断的代码.啥叫魔术数字呢,举个例子,要置顶一个文章的时候先判断文章是不是已发布状态. if (article.state == 2) {    // state 2 代表文章已发布 } 假如我们的代码里没有注释,或者等我们项目的代码里充斥着这些魔术数字

  • javascript实现Emrips反质数枚举的示例代码

    今天看到一个kata,提出一个"emirps"的概念:一个质数倒转后得到的是一个不同的质数,这个数叫做"emirps". 例如:13,17是质数,31,71也是质数,13和17是"emirps". 但是质数757,787,797是回文质数,这意味着反转的数字与原始数字相同,所以它们不被认为是"emirps". 题目要求写一个函数输入一个正整数n,返回小于n的"emirps"的个数,其中最大"emi

  • C语言责任链模式示例代码

    目录 介绍: 作用: 类比: 示例: 总结 介绍: ​ 责任链模式是一种行为模式,它可以允许你将请求沿着处理者链进行发送,收到请求以后, 每个处理者均可对请求进行处理, 或将其传递给链上的下个处理者: 作用: 将请求按照链的方式一一传递 类比: ​ 公司申请报销,首先要leader审批通过,然后是HR,再然后是财务,最后是老板,一级一级的将请求传递: 示例: #include <stdio.h> #include <assert.h> #include "list.h&q

  • C语言打印杨辉三角形的示例代码

    目录 1. 题目描述 2. 解题思路 3. 动图演示 4. 代码实现 Step1 Step2 居中显示 5. 完整代码 6. 特性总结 1. 题目描述 杨辉三角形 解题之前,我们先来了解一下杨辉三角形到底是什么? 杨辉三角形,又称帕斯卡三角形.贾宪三角形.海亚姆三角形,它的排列形如三角形. 因为首现于南宋杨辉的<详解九章算法>得名,而书中杨辉说明是引自贾宪的<释锁算书>,故又名贾宪三角形. 古代波斯数学家欧玛尔·海亚姆也描述过这个三角形.在欧洲,因为法国数学家布莱兹‧帕斯卡在165

  • go语言实现屏幕截图的示例代码

    目录 借助第三方库 安装 自定义截图 Capture 全屏截图 CaptureDisplay 获取活动显示器数量 NumActiveDisplays 获取指定屏幕显示范围 GetDisplayBounds 获取自定义矩形区域的截图 CaptureRect 演示 借助第三方库 https://github.com/kbinani/screenshot 安装 go get github.com/kbinani/screenshot 方法 详情查看https://pkg.go.dev/github.c

  • C语言实现栈的示例代码

    目录 一.了解栈的结构特点 二.具体实现 补充 栈的用处 一.了解栈的结构特点 栈是一种特殊的线性表,只允许从一端进出数据,称为后进先出,先进后出. 压栈:栈的插入操作叫做进栈/压栈/入栈,入数据在栈顶 出栈:栈的删除操作叫做出栈.出数据也在栈顶 二.具体实现 由于栈实质是一种线性表,因此可以用两种方式来实现:顺序表  或  链表 这里我使用的是类似顺序表的方式来实现. 代码如下: typedef char Stacktype; typedef struct Stack { int top; S

  • C语言实现通讯录的示例代码

    目录 一.Contact.h文件 二.Contact.c文件 三.test.c文件 一.Contact.h文件 包含函数的声明 #pragma once #define _CRT_SECURE_NO_WARNINGS 1 #include <stdio.h> #include <string.h> #include <stdlib.h> #include <assert.h> #define MAX 100 #define MAX_NAME 20 #defi

  • c语言中&的用法示例代码

    1.用于指针赋值 #include<stdio.h> int main() { int a = 2; int*b;//定义一个整形指针 b = &a;//给指针赋值,使指针指向a的地址 printf("%d", b);//输出的是a的地址 printf("\n");//换行符 printf("%d", *b);//*的作用是解引用,取出指针指向地址的内容,达到简 return 0; } 2.用于二目运算中的按位(位运算)与运算

  • spring boot mybatis枚举映射示例代码

    前言 在mybatis和mybatis plus里,如果你的实体字段是一个枚举类型,而在数据表里是整型,这时在存储时需要进行处理,默认情况下,会把枚举的元素名称拼接到SQL语句里,而由于数据表是int类型,所以在插入等操作时,就会出现异常! 添加枚举处理器 MappedTypes(value = {YesOrNo.class}) public class UniversalEnumHandler<E extends Enum<E> & BaseEnum> extends B

  • C语言数据类型枚举enum全面详解示例教程

    目录 一.枚举类型的定义 二.枚举类型的使用 2.1创建变量 2.2一些优点 总结 一.枚举类型的定义 enum Day//enum Day是一种类型 { Mon,//周一到周日这些叫枚举的可能取值,也叫枚举常量 Tue, Wed, Thur, Fri, Sat, Sun, }; 上述代码定义的enum Day是一种枚举类型,{}中内容是枚举类型的可能取值,也可叫作枚举常量. 这些枚举常量都是有值的,默认从0开始,依次往后递增1,如果你愿意赋值也是可以的. 代码如下: #include<stdi

随机推荐