目錄
定义新类型实现枚举" >定义新类型实现枚举
protobuf中生成的枚举代码" >protobuf中生成的枚举代码
首頁 後端開發 Golang 夥計,Go專案怎麼使用枚舉?

夥計,Go專案怎麼使用枚舉?

Aug 04, 2023 pm 05:25 PM
go 列舉

前言

枚舉是一種很重要的資料類型,在javaC語言等主流程式語言中都支援了枚舉類型,但是在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语言的两个特性:常量和定义新类型来实现枚举,方法总比困难多吗,开源库是优秀的,我们往往可以从高手那里里学习很多,记住,请永远保持一个学徒之心;

以上是夥計,Go專案怎麼使用枚舉?的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

Go WebSocket 訊息如何發送? Go WebSocket 訊息如何發送? Jun 03, 2024 pm 04:53 PM

在Go中,可以使用gorilla/websocket包發送WebSocket訊息。具體步驟:建立WebSocket連線。傳送文字訊息:呼叫WriteMessage(websocket.TextMessage,[]byte("訊息"))。發送二進位訊息:呼叫WriteMessage(websocket.BinaryMessage,[]byte{1,2,3})。

Golang 與 Go 語言的區別 Golang 與 Go 語言的區別 May 31, 2024 pm 08:10 PM

Go和Go語言是不同的實體,具有不同的特性。 Go(又稱Golang)以其並發性、編譯速度快、記憶體管理和跨平台優點而聞名。 Go語言的缺點包括生態系統不如其他語言豐富、文法更嚴格、缺乏動態類型。

如何在 Go 中使用正規表示式匹配時間戳記? 如何在 Go 中使用正規表示式匹配時間戳記? Jun 02, 2024 am 09:00 AM

在Go中,可以使用正規表示式比對時間戳記:編譯正規表示式字串,例如用於匹配ISO8601時間戳記的表達式:^\d{4}-\d{2}-\d{2}T \d{2}:\d{2}:\d{2}(\.\d+)?(Z|[+-][0-9]{2}:[0-9]{2})$ 。使用regexp.MatchString函數檢查字串是否與正規表示式相符。

Golang 技術效能優化中如何避免記憶體洩漏? Golang 技術效能優化中如何避免記憶體洩漏? Jun 04, 2024 pm 12:27 PM

記憶體洩漏會導致Go程式記憶體不斷增加,可通過:關閉不再使用的資源,如檔案、網路連線和資料庫連線。使用弱引用防止記憶體洩漏,當物件不再被強引用時將其作為垃圾回收目標。利用go協程,協程棧記憶體會在退出時自動釋放,避免記憶體洩漏。

PHP 8.1中的枚舉(枚舉)是什麼? PHP 8.1中的枚舉(枚舉)是什麼? Apr 03, 2025 am 12:05 AM

PHP8.1中的枚舉功能通過定義命名常量增強了代碼的清晰度和類型安全性。 1)枚舉可以是整數、字符串或對象,提高了代碼可讀性和類型安全性。 2)枚舉基於類,支持面向對象特性,如遍歷和反射。 3)枚舉可用於比較和賦值,確保類型安全。 4)枚舉支持添加方法,實現複雜邏輯。 5)嚴格類型檢查和錯誤處理可避免常見錯誤。 6)枚舉減少魔法值,提升可維護性,但需注意性能優化。

Golang 函數接收 map 參數時的注意事項 Golang 函數接收 map 參數時的注意事項 Jun 04, 2024 am 10:31 AM

在Go中傳遞map給函數時,預設會建立副本,對副本的修改不影響原map。如果需要修改原始map,可透過指標傳遞。空map需小心處理,因為技術上是nil指針,傳遞空map給期望非空map的函數會發生錯誤。

如何使用 Golang 的錯誤包裝器? 如何使用 Golang 的錯誤包裝器? Jun 03, 2024 pm 04:08 PM

在Golang中,錯誤包裝器允許你在原始錯誤上追加上下文訊息,從而創建新錯誤。這可用於統一不同程式庫或元件拋出的錯誤類型,簡化偵錯和錯誤處理。步驟如下:使用errors.Wrap函數將原有錯誤包裝成新錯誤。新錯誤包含原始錯誤的上下文資訊。使用fmt.Printf輸出包裝後的錯誤,提供更多上下文和可操作性。在處理不同類型的錯誤時,使用errors.Wrap函數統一錯誤類型。

Go 並發函數的單元測試指南 Go 並發函數的單元測試指南 May 03, 2024 am 10:54 AM

對並發函數進行單元測試至關重要,因為這有助於確保其在並發環境中的正確行為。測試並發函數時必須考慮互斥、同步和隔離等基本原理。可以透過模擬、測試競爭條件和驗證結果等方法對並發函數進行單元測試。

See all articles