掃二維碼與項(xiàng)目經(jīng)理溝通
我們在微信上24小時(shí)期待你的聲音
解答本文疑問/技術(shù)咨詢/運(yùn)營咨詢/技術(shù)建議/互聯(lián)網(wǎng)交流
枚舉的本質(zhì)是什么,我們天天寫代碼用枚舉,那啥是枚舉啊。wiki上是這么說的

用人話說就是
枚舉是強(qiáng)類型編程語言中的一種類型,由一組名稱和值組成。通常用來在編程語言中充當(dāng)常量的標(biāo)識符。
沒毛病,我們也確實(shí)是這樣使用的。比如上學(xué)的時(shí)候,經(jīng)常寫c的小玩具代碼,c標(biāo)準(zhǔn)里面提供了enum關(guān)鍵字,寫起來比較直白,使用的時(shí)候和struct類似,需要enum week這樣寫,c里面默認(rèn)枚舉值是從0開始,int類型,其實(shí)c里面就是把枚舉當(dāng)做int類型來用的。
- #include
- enum week{Mon, Tue, Wed, Thur, Fri, Sat, Sun};
- int main()
- {
- enum week day; // 需要加 enum 關(guān)鍵字
- day = Wed;
- printf("%d",day); // 輸出 2
- int i;
- for (i=Mon; i<=Sun; i++){ // 可以直接把枚舉類型賦值給int類型
- printf("%d ", i); // 輸出 0,1,2,3,4,5,6
- }
- return 0;
- }
上面的例子沒問題,在初始化的時(shí)候,枚舉值默認(rèn)情況下,編譯器會從分配0開始的值,例如上面的Mon=0,Tue=1…,但是也會想不按照編譯器的默認(rèn)分配方式,由我自己分配,那怎么寫呢,看下面的例子:
- #include
- enum day {sunday = 1, monday, tuesday = 5,
- wednesday, thursday = 10, friday, saturday};
- int main()
- {
- printf("%d %d %d %d %d %d %d", sunday, monday, tuesday,
- wednesday, thursday, friday, saturday); // 輸出1 2 5 6 10 11 12
- return 0;
- }
也就是說,枚舉里面可以按任何順序?qū)⒅捣峙浣o某個(gè)名稱。所有未分配的名稱都會把值作為前一個(gè)名稱的值加一。
其實(shí),定義幾個(gè)常量的事,是不是用宏這個(gè)東西更好呢,比如這么寫
- #define sunday 0
- #define monday 1
- #define tuesday 2
但是老師說了,盡量別用宏,不是說宏不好,宏也好,編譯器替換,沒有運(yùn)行期啥事,多快啊,但是有幾個(gè)問題:
1)宏沒有作用域一說 2)枚舉是類型安全的
扯的有點(diǎn)遠(yuǎn)了,現(xiàn)在回來看看Go里面的枚舉怎么寫。當(dāng)然也很簡單了,官方教導(dǎo)我們這么寫:
- type ByteSize float64
- const (
- _ = iota
- KB ByteSize = 1 << (10 * iota)
- MB
- GB
- )
Go里面更簡潔了,直接把enum關(guān)鍵字去掉了,其實(shí)從Go的角度看,枚舉不就是常量么,搞這么多語法糖干嘛,Go里面提供了一個(gè)關(guān)鍵字iota可以實(shí)現(xiàn)常量的遞增,同時(shí)也支持手動賦值,iota和手動賦值結(jié)合起來,就可以實(shí)現(xiàn)類似c里面的效果
- const (
- A0 = iota
- A1 = iota
- A2 = iota
- )
- fmt.Println(A0, A1, A2) // "0 1 2"
可以 簡寫成這樣
- const (
- A0 = iota
- A1
- A2
- )
也可以從1開始
- const (
- A1 = iota + 1
- A2
- A3
- )
- fmt.Println(A1, A2, A3) // "1 2 3"
或者跳過某個(gè)值
- const (
- C1 = iota + 1
- _
- C3
- C4
- )
- fmt.Println(C1, C3, C4) // "1 3 4"
看到這里你或許有個(gè)疑問,這里的枚舉其實(shí)就是常量么,那怎么寫是字符串類型的枚舉呢,你可能會說,當(dāng)然是用字符串常量了。但是那只是字符串常量了,沒有枚舉的性質(zhì)。我可能想要的是一種字符串到值的枚舉類型。思考再三,看我這種寫法是否可以:
- type Direction int
- const (
- North Direction = iota
- East
- South
- West
- )
- func (d Direction) String() string {
- return [...]string{"North", "East", "South", "West"}[d]
- }
使用的時(shí)候
- var d Direction = North
- fmt.Print(d)
- switch d {
- case North:
- fmt.Println(" goes up.")
- case South:
- fmt.Println(" goes down.")
- default:
- fmt.Println(" stays put.")
- }
當(dāng)然還有一種方法,比較stupid
- type weekday string
- func (w weekday) isWeekday() weekday {
- return w
- }
- type Weekday interface {
- isWeekday() weekday
- }
- const (
- Monday = weekday("Monday")
- Tuesday = weekday("Tuesday")
- Wendsday = weekday("Wendsday")
- Thursday = weekday("Thursday")
- Friday = weekday("Friday")
- Saturday = weekday("Saturday")
- Sunday = weekday("Sunday")
- )
- // 使用
- func main() {
- var d1 = weekday.Monday
- var d2 = weekday.Tuesday
- fmt.Println(d1, d2, d1 == d2, d1 == weekday.Monday)
- }
如果使用struct表示枚舉,那其實(shí)還可以使用反射的方式,比如下面這樣寫:
- import (
- "reflect"
- )
- type weekday struct {
- Monday, Tuesday, Wendsday, Thursday, Friday, Saturday, Sunday int
- }
- func (c weekday) Get(id string) int {
- vo := reflect.ValueOf(c)
- typeVo := vo.Type()
- for i := 0; i < vo.NumField(); i++ {
- if typeVo.Field(i).Name == id {
- return vo.Field(i).Interface().(int)
- }
- }
- return 0
- }
- var weekdayEnum = weekday {
- Monday: 1,
- Tuesday: 2,
- Wendsday: 3,
- Thursday: 4,
- Friday: 5,
- Saturday: 6,
- Sunday: 7
- }
本文轉(zhuǎn)載自微信公眾號「碼小菜」,可以通過以下二維碼關(guān)注。轉(zhuǎn)載本文請聯(lián)系碼小菜公眾號。

我們在微信上24小時(shí)期待你的聲音
解答本文疑問/技術(shù)咨詢/運(yùn)營咨詢/技術(shù)建議/互聯(lián)網(wǎng)交流