網站首頁 編程語言 正文
前言
哈嘍,大家好,我是asong。枚舉是一種很重要的數據類型,在java、C語言等主流編程語言中都支持了枚舉類型,但是在Go語言中卻沒有枚舉類型,那有什么替代方案嗎? 本文我們來聊一聊這個事情;
為什么要有枚舉
我們以java語言為例子,在JDK1.5之前沒有枚舉類型,我們通常會使用int常量來表示枚舉,一般使用如下:
public static final int COLOR_RED = 1;
public static final int COLOR_BLUE = 2;
public static final int COLOR_GREEN = 3;
使用int類型會存在以下隱患:
- 不具備安全性,聲明時如果沒有使用final就會造成值被篡改的風險;
- 語義不夠明確,打印int型數字并不知道其具體含義
于是乎我們就想到用常量字符來表示,代碼就變成了這樣:
public static final String COLOR_RED = "RED";
public static final String COLOR_BLUE = "BLUE";
public static final String COLOR_GREEN = "GREEN";
這樣也同樣存在問題,因為我們使用的常量字符,那么有些程序猿不按套路出牌就可以使用字符串的值進行比較,這樣的代碼會被不斷模仿變得越來越多的,然后屎山就出現了;
所以我們迫切需要枚舉類型的出現來起到約束的作用,假設使用一個枚舉類型做入參,枚舉類型就可以限定沙雕用戶不按套路傳參,這樣就可以懟他了,哈哈~;
使用枚舉的代碼就可以變成這樣,傳了枚舉之外的類型都不可以了;
public class EnumClass {
? ? public static void main(String [] args){
? ? ? ? Color color = Color.RED;
? ? ? ? convert(color);
? ? ? ? System.out.println(color.name());
? ? }
? ? public static void convert(Color c){
? ? ? ? System.out.println(c.name());
? ? }
}
enum Color{
? ? RED,BLUE,GREEN;
}
Go語言就沒有枚舉類型,我們該使用什么方法來替代呢?
定義新類型實現枚舉
枚舉通常是一組相關的常量集合,Go語言中有提供常量類型,所以我們可以使用常量來聲明枚舉,但也同樣會遇到上述的問題,起不到約束的作用,所以為了起到約束我們可以使用Go語言另外一個知識點 -- 類型定義,Go語言中可以使用type關鍵字定義不同的類型,我們可以為整型、浮點型、字符型等定義新的類型,新的類型與原類型轉換需要顯式轉換,這樣在一定程度上也起到了約束的作用,我們就可以用Go語言實現如下枚舉:
type OrderStatus int const ( ?? ?CREATE OrderStatus = iota + 1 ?? ?PAID ?? ?DELIVERING ?? ?COMPLETED ?? ?CANCELLED ) func main() { ?? ?a := 100 ?? ?IsCreated(a) }
上面的代碼就會報錯:
./main.go:19:12: cannot use a (variable of type int) as type OrderStatus in argument to IsCreated
定義新的類型可以起到約束作用,比如我們要檢查狀態機,入參限定了必須是OrderStatus類型,如果是int類型就會報錯。
上面我們的枚舉實現方式只能獲取枚舉值,獲取不到其映射的字面意思,所以我們可以優化一下,實現String方法,使用官方提供的cmd/string來快速實現,代碼如下:
//go:generate stringer -type=OrderStatus type OrderStatus int const ( ?? ?CREATE OrderStatus = iota + 1 ?? ?PAID ?? ?DELIVERING ?? ?COMPLETED ?? ?CANCELLED )
執行命令go generate ./...生成orderstatus_string.go文件:
import "strconv" func _() { ?? ?// An "invalid array index" compiler error signifies that the constant values have changed. ?? ?// Re-run the stringer command to generate them again. ?? ?var x [1]struct{} ?? ?_ = x[CREATE-1] ?? ?_ = x[PAID-2] ?? ?_ = x[DELIVERING-3] ?? ?_ = x[COMPLETED-4] ?? ?_ = x[CANCELLED-5] } const _OrderStatus_name = "CREATEPAIDDELIVERINGCOMPLETEDCANCELLED" var _OrderStatus_index = [...]uint8{0, 6, 10, 20, 29, 38} func (i OrderStatus) String() string { ?? ?i -= 1 ?? ?if i < 0 || i >= OrderStatus(len(_OrderStatus_index)-1) { ?? ??? ?return "OrderStatus(" + strconv.FormatInt(int64(i+1), 10) + ")" ?? ?} ?? ?return _OrderStatus_name[_OrderStatus_index[i]:_OrderStatus_index[i+1]] }
protobuf中生成的枚舉代碼
Go語言使用protobuf會生成對應的枚舉代碼,我們發現其中也是使用定義新的類型的方式來實現的,然后在封裝一些方法,我們來賞析一下protobuf生成的枚舉代碼:
const ( ?? ?CREATED ?OrderStatus = 1 ?? ?PAID OrderStatus = 2 ?? ?CANCELED OrderStatus = 3 ) var OrderStatus_name = map[int32]string{ ?? ?1: "CREATED", ?? ?2: "PAID", ?? ?3: "CANCELED", } var OrderStatus_value = map[string]int32{ ?? ?"CREATED": ?1, ?? ?"PAID": 2, ?? ?"CANCELED": 3, } func (x OrderStatus) Enum() *OrderStatus { ?? ?p := new(OrderStatus) ?? ?*p = x ?? ?return p } func (x OrderStatus) String() string { ?? ?return proto.EnumName(OrderStatus_name, int32(x)) } func (x *OrderStatus) UnmarshalJSON(data []byte) error { ?? ?value, err := proto.UnmarshalJSONEnum(OrderStatus_value, data, "OrderStatus") ?? ?if err != nil { ?? ??? ?return err ?? ?} ?? ?*x = OrderStatus(value) ?? ?return nil }
總結
雖然Go語言沒有提供枚舉類型,但是我們也可以根據Go語言的兩個特性:常量和定義新類型來實現枚舉,方法總比困難多嗎,開源庫是優秀的,我們往往可以從高手那里里學習很多,記住,請永遠保持一個學徒之心;
原文鏈接:https://juejin.cn/post/7134265331597443080
相關推薦
- 2022-06-10 ASP.NET?Core為Ocelot網關配置Swagger_實用技巧
- 2022-11-01 Flaks基礎之在URL中添加變量的實現詳解_python
- 2022-10-01 SQL中concat和substr組合運用解析_MsSql
- 2021-12-02 C++11標準庫bind函數應用教程_C 語言
- 2022-02-05 Tableau:如何處理Excel中一個sheet中有多張表的問題?
- 2023-09-17 org.apache.ibaorg.apache.ibatis.btis.binding.Bindi
- 2022-06-06 elementUI基礎的引入和使用
- 2022-06-08 Android即時通訊設計(騰訊IM接入和WebSocket接入)_Android
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支