Go項(xiàng)目怎么使用枚舉
前言
哈嘍,大家好,我是asong。枚舉是一種很重要的數(shù)據(jù)類型,在java、C語(yǔ)言等主流編程語(yǔ)言中都支持了枚舉類型,但是在Go語(yǔ)言中卻沒(méi)有枚舉類型,那有什么替代方案嗎? 本文我們來(lái)聊一聊這個(gè)事情;
為什么要有枚舉
我們以java語(yǔ)言為例子,在JDK1.5之前沒(méi)有枚舉類型,我們通常會(huì)使用int常量來(lái)表示枚舉,一般使用如下:
public static final int COLOR_RED = 1; public static final int COLOR_BLUE = 2; public static final int COLOR_GREEN = 3;
使用int類型會(huì)存在以下隱患:
- 不具備安全性,聲明時(shí)如果沒(méi)有使用final就會(huì)造成值被篡改的風(fēng)險(xiǎn);
- 語(yǔ)義不夠明確,打印int型數(shù)字并不知道其具體含義
于是乎我們就想到用常量字符來(lái)表示,代碼就變成了這樣:
public static final String COLOR_RED = "RED"; public static final String COLOR_BLUE = "BLUE"; public static final String COLOR_GREEN = "GREEN";
這樣也同樣存在問(wèn)題,因?yàn)槲覀兪褂玫某A孔址?,那么有些程序猿不按套路出牌就可以使用字符串的值進(jìn)行比較,這樣的代碼會(huì)被不斷模仿變得越來(lái)越多的,然后屎山就出現(xiàn)了;
所以我們迫切需要枚舉類型的出現(xiàn)來(lái)起到約束的作用,假設(shè)使用一個(gè)枚舉類型做入?yún)?,枚舉類型就可以限定沙雕用戶不按套路傳參,這樣就可以懟他了,哈哈~;
使用枚舉的代碼就可以變成這樣,傳了枚舉之外的類型都不可以了;
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語(yǔ)言就沒(méi)有枚舉類型,我們?cè)撌褂檬裁捶椒▉?lái)替代呢?
定義新類型實(shí)現(xiàn)枚舉
枚舉通常是一組相關(guān)的常量集合,Go語(yǔ)言中有提供常量類型,所以我們可以使用常量來(lái)聲明枚舉,但也同樣會(huì)遇到上述的問(wèn)題,起不到約束的作用,所以為了起到約束我們可以使用Go語(yǔ)言另外一個(gè)知識(shí)點(diǎn) -- 類型定義,Go語(yǔ)言中可以使用type關(guān)鍵字定義不同的類型,我們可以為整型、浮點(diǎn)型、字符型等定義新的類型,新的類型與原類型轉(zhuǎn)換需要顯式轉(zhuǎn)換,這樣在一定程度上也起到了約束的作用,我們就可以用Go語(yǔ)言實(shí)現(xiàn)如下枚舉:
type OrderStatus int
const (
?? ?CREATE OrderStatus = iota + 1
?? ?PAID
?? ?DELIVERING
?? ?COMPLETED
?? ?CANCELLED
)
func main() {
?? ?a := 100
?? ?IsCreated(a)
}上面的代碼就會(huì)報(bào)錯(cuò):
./main.go:19:12: cannot use a (variable of type int) as type OrderStatus in argument to IsCreated
定義新的類型可以起到約束作用,比如我們要檢查狀態(tài)機(jī),入?yún)⑾薅吮仨毷荗rderStatus類型,如果是int類型就會(huì)報(bào)錯(cuò)。
上面我們的枚舉實(shí)現(xiàn)方式只能獲取枚舉值,獲取不到其映射的字面意思,所以我們可以優(yōu)化一下,實(shí)現(xiàn)String方法,使用官方提供的cmd/string來(lái)快速實(shí)現(xiàn),代碼如下:
//go:generate stringer -type=OrderStatus type OrderStatus int const ( ?? ?CREATE OrderStatus = iota + 1 ?? ?PAID ?? ?DELIVERING ?? ?COMPLETED ?? ?CANCELLED )
執(zhí)行命令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語(yǔ)言使用protobuf會(huì)生成對(duì)應(yīng)的枚舉代碼,我們發(fā)現(xiàn)其中也是使用定義新的類型的方式來(lái)實(shí)現(xiàn)的,然后在封裝一些方法,我們來(lái)賞析一下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
}總結(jié)
雖然Go語(yǔ)言沒(méi)有提供枚舉類型,但是我們也可以根據(jù)Go語(yǔ)言的兩個(gè)特性:常量和定義新類型來(lái)實(shí)現(xiàn)枚舉,方法總比困難多嗎,開(kāi)源庫(kù)是優(yōu)秀的,我們往往可以從高手那里里學(xué)習(xí)很多,記住,請(qǐng)永遠(yuǎn)保持一個(gè)學(xué)徒之心;
到此這篇關(guān)于Go項(xiàng)目怎么使用枚舉的文章就介紹到這了,更多相關(guān)Go 枚舉內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Go開(kāi)發(fā)環(huán)境搭建詳細(xì)介紹
由于目前網(wǎng)上Go的開(kāi)發(fā)環(huán)境搭建文章很多,有些比較老舊,都是基于 GOPATH的,給新入門的同學(xué)造成困擾。以下為2023 版 Go 開(kāi)發(fā)環(huán)境搭建,可參照此教程搭建Go開(kāi)發(fā)環(huán)境,有需要的朋友可以參考閱讀2023-04-04
深度剖析Golang如何實(shí)現(xiàn)GC掃描對(duì)象
這篇文章主要為大家詳細(xì)介紹了Golang是如何實(shí)現(xiàn)GC掃描對(duì)象的,文中的示例代碼講解詳細(xì),具有一定的學(xué)習(xí)價(jià)值,需要的小伙伴可以參考一下2023-03-03
golang實(shí)現(xiàn)基于channel的通用連接池詳解
這篇文章主要給大家介紹了關(guān)于golang實(shí)現(xiàn)基于channel的通用連接池的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧。2018-02-02
Go語(yǔ)言實(shí)現(xiàn)基于websocket瀏覽器通知功能
這篇文章主要介紹了Go語(yǔ)言實(shí)現(xiàn)基于websocket瀏覽器通知功能,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-07-07
Go語(yǔ)言中處理JSON數(shù)據(jù)的編碼和解碼的方法
在Go語(yǔ)言中,處理JSON數(shù)據(jù)的編碼和解碼主要依賴于標(biāo)準(zhǔn)庫(kù)中的encoding/json包,這個(gè)包提供了兩個(gè)核心的函數(shù):Marshal和Unmarshal,本文給大家介紹了Go語(yǔ)言中處理JSON數(shù)據(jù)的編碼和解碼的方法,需要的朋友可以參考下2024-04-04
Golang基礎(chǔ)教程之字符串string實(shí)例詳解
這篇文章主要給大家介紹了關(guān)于Golang基礎(chǔ)教程之字符串string的相關(guān)資料,需要的朋友可以參考下2022-07-07

