Go語言模擬列舉(const和iota模擬列舉)

2020-07-16 10:05:11
Go語言現階段沒有列舉型別,但是可以使用 const 常數配合上一節《Go語言常數》中介紹的 iota 來模擬列舉型別,請看下面的程式碼:
type Weapon int

const (
     Arrow Weapon = iota    // 開始生成列舉值, 預設為0
     Shuriken
     SniperRifle
     Rifle
     Blower
)

// 輸出所有列舉值
fmt.Println(Arrow, Shuriken, SniperRifle, Rifle, Blower)

// 使用列舉型別並賦初值
var weapon Weapon = Blower
fmt.Println(weapon)
程式碼輸出如下:

0 1 2 3 4
4

程式碼說明如下:
第 1 行中,將 int 定義為 Weapon 型別,就像列舉型別的本質是一個 int 型別一樣。當然,某些情況下,如果需要 int32 和 int64 的列舉,也是可以的。

第 4 行中,將常數 Arrow 的型別標識為 Weapon,這樣標識後,const 下方的常數可以使用 Weapon 作為預設型別。該行使用 iota 進行常數值自動生成,iota 的起始值為 0,一般情況下也是建議列舉從 0 開始,讓每個列舉型別都有一個空值,方便業務和邏輯的靈活使用。

一個 const 宣告內的每一行常數宣告,將會自動套用前面的 iota 格式,並自動增加,類似於電子試算表中單元格自動填充的效果,只需要建立好單元格之間的變化關係,拖動右下方的小點就可以自動生成單元格的值。

當然,iota 不僅可以生成每次增加 1 的列舉值。還可以利用 iota 來做一些強大的列舉常數值生成器。下面的程式碼可以方便的生成標誌位常數:
const (
    FlagNone = 1 << iota
    FlagRed
    FlagGreen
    FlagBlue
)

fmt.Printf("%d %d %dn", FlagRed, FlagGreen, FlagBlue)
fmt.Printf("%b %b %bn", FlagRed, FlagGreen, FlagBlue)
程式碼輸出如下:

2 4 8
10 100 1000

在程式碼中編寫一些標誌位時,我們往往手動編寫常數值,常數值特別多時,很容易重複或者寫錯,因此,使用 ioto 自動生成更加方便。

程式碼說明如下:
  • 第 2 行中 iota 使用了一個移位元運算,每次將上一次的值左移一位(二進位制位),以得出每一位的常數值。
  • 第 8 行,將 3 個列舉按照常數輸出,分別輸出 2、4、8,都是將 1 每次左移一位的結果。
  • 第 9 行,將列舉值按二進位制格式輸出,可以清晰地看到每一位的變化。

將列舉值轉換為字串

列舉在 C# 中是一個獨立的型別,可以通過列舉值獲取該值對應的字串。例如,C# 中 Week 列舉值 Monday 為 1,那麼可以通過 Week.Monday.ToString() 函數獲得 Monday 字串。

Go語言中也可以實現這一功能,程式碼如下所示:

轉換字串:
package main

import "fmt"

// 宣告晶片型別
type ChipType int

const (
    None ChipType = iota
    CPU    // 中央處理器
    GPU    // 圖形處理器
)

func (c ChipType) String() string {
    switch c {
    case None:
        return "None"
    case CPU:
        return "CPU"
    case GPU:
        return "GPU"
    }

    return "N/A"
}

func main() {

    // 輸出CPU的值並以整型格式顯示
    fmt.Printf("%s %d", CPU, CPU)
}
執行結果:

CPU 1

程式碼說明如下:
  • 第 6 行,將 int 宣告為 ChipType 晶片型別。
  • 第 9 行,將 const 裡定義的常數值設為 ChipType 型別,且從 0 開始,每行值加 1。
  • 第 14 行,定義 ChipType 型別的方法 String(),返回值為字串型別。
  • 第 15~22 行,使用 switch 語句判斷當前的 ChitType 型別的值,返回對應的字串。
  • 第 30 行,按整型的格式輸出 CPU 的值。

String() 方法的 ChipType 在使用上和普通的常數沒有區別。當這個型別需要顯示為字串時,Go語言會自動尋找 String() 方法並進行呼叫。