3
1

More than 1 year has passed since last update.

[Golang] enumを使いたい ~ structでも定数定義できるぞ

Last updated at Posted at 2022-02-19

元々Javaエンジニアの私ですが、最近Goを趣味で使い始めたのでメモ程度に。
今回はJavaでよく使うenumをGoでもそれっぽく使う方法を残しておきます。

まずは基本的な使い方

よくGoogleで検索して見かけるやつ

hoge1.go
package constant

// 自動で採番してくれる
const (
    HOGE1_1_1 = iota // 0
    HOGE1_1_2 =      // 1
    HOGE1_1_3 =      // 2
)

// 1始まりにしたい
const (
    HOGE1_2_1 = 1
    HOGE1_2_2 = 2
    HOGE1_2_3 = 3
)

// 文字列で定義したい
const (
    HOGE1_3_1 = "hoge1"
    HOGE1_3_2 = "hoge2"
    HOGE1_3_3 = "hoge3"
)

// 基本型をベースにした独自の型で定義したい
type HOGE uint8
const (
    HOGE1_4_1 HOGE = 1
    HOGE1_4_2 HOGE = 2
    HOGE1_4_3 HOGE = 3
)

大体の定数って数値か文字列のどれかで扱うことが多いので以上のような定数宣言をよく見かける。

struct(構造体)でも宣言がしたい! でもうまくいかない。

そう思ってこう書きがちですが...

hoge2_ng.go
package constant

type Hoge2NG struct {
    Code uint8
    Name string
}

const (
    HOGE2_NG1 = Hoge2NG{Code: 1, Name: "hoge1"}
    HOGE2_NG2 = Hoge2NG{Code: 2, Name: "hoge2"}
    HOGE2_NG3 = Hoge2NG{Code: 3, Name: "hoge3"}
)

もちろん、これではダメです。

ではどうするか?

こうしちゃう!

結論

hoge2_ok.go
package constant

type hoge2OK struct {
    code uint8
    name string
}

var (
    HOGE2_OK1 = hoge2OK{code: 1, name: "hoge1"}
    HOGE2_OK2 = hoge2OK{code: 2, name: "hoge2"}
    HOGE2_OK3 = hoge2OK{code: 3, name: "hoge3"}
)

func (v *hoge2OK) Code() uint8 {
    return v.code
}

func (v *hoge2OK) Name() string {
    return v.name
}

func GetHoge2List() []mobileNetwork {
    list := make([]mobileNetwork, 0)
    list = append(list, HOGE2_OK1)
    list = append(list, HOGE2_OK2)
    list = append(list, HOGE2_OK3)
    return list
}

func GetHoge2Name(code uint8) string {
    list := GetMobileNetworkList()
    for _, v := range list {
        if code == v.code {
            return v.name
        }
    }
    return ""
}

解説

まずは「定数 = const」という考え方をやめます。
定数をvar(変数)として宣言してしまうことでstructで宣言することが可能になります。
ここでのポイントが、struct宣言の時は外部参照できないように先頭小文字、structのフィールドも先頭小文字で定義します。

type hoge2OK struct {
    code uint8
    name string
}

var (
    HOGE2_OK1 = hoge2OK{code: 1, name: "hoge1"}
    HOGE2_OK2 = hoge2OK{code: 2, name: "hoge2"}
    HOGE2_OK3 = hoge2OK{code: 3, name: "hoge3"}
)

でもこのままだと「codeだけ」「nameだけ」を取得したいといったことができなくなるので、外部からアクセスできる処理を追加します。

func (v *hoge2OK) Code() uint8 {
    return v.code
}

func (v *hoge2OK) Name() string {
    return v.name
}

外部から使うときはこうすると各フィールドの値が取得できる。

main.go
package main

func main() {
    constant.HOGE2_OK1.Code() // uint8(1)
    constant.HOGE2_OK1.Name() // "hoge1"
}

「でもenumのようにリスト取得できないじゃん!!」

と思ったそこのアナタ。
大変面倒ですがリスト取得用の処理を追加します。

func GetHoge2List() []mobileNetwork {
    list := make([]mobileNetwork, 0)
    list = append(list, HOGE2_OK1)
    list = append(list, HOGE2_OK2)
    list = append(list, HOGE2_OK3)
    return list
}

そしてenumでもおまじないのように書かれている、「コードから名称を取得する処理」も一緒に追加。(いらなかったらなくてもOK)
既に追加したリスト取得用処理を使えば簡単にできます。

func GetHoge2Name(code uint8) string {
    list := GetMobileNetworkList()
    for _, v := range list {
        if code == v.code {
            return v.name
        }
    }
    return ""
}

番外編

Googleで検索かけると「コードから名称を取得する処理」でこんなコードが出てきますが...

func GetHoge2Name(code uint8) string {
    if code == HOGE2_OK1.code {
        return HOGE2_OK1.name
    }
    if code == HOGE2_OK2.code {
        return HOGE2_OK2.name
    }
    if code == HOGE2_OK3.code {
        return HOGE2_OK3.name
    }
    return ""
}

事故りそうだしこんなの書きたくない!!

3
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1