Skip to content

Instantly share code, notes, and snippets.

@hatappo
Created July 14, 2021 18:34
Show Gist options
  • Select an option

  • Save hatappo/1b06eb02168e835ada591c4551143f0b to your computer and use it in GitHub Desktop.

Select an option

Save hatappo/1b06eb02168e835ada591c4551143f0b to your computer and use it in GitHub Desktop.
Golang で enum をどう実装するか
package main
import (
"fmt"
enum "github.com/hatappo/go-skelton/main/enum"
)
func main() {
hoge := enum.SeasonValueOf("ほげ")
fmt.Printf("'ほげ' は '%s' の季節です。\n", hoge.Ja())
fmt.Println("--------------------")
w := enum.SeasonValueOf("WINTER")
fmt.Printf("'WINTER' は日本語だと '%s' です。\n", w.Ja())
fmt.Printf("'WINTER' は英語ならば '%s' です。\n", w.En())
fmt.Printf("'WINTER' の次の季節は '%s' です。\n", w.Next().En()+"("+w.Next().Ja()+")")
fmt.Println("--------------------")
a := enum.SeasonValueOf("秋")
fmt.Printf("'%s' は '%s' の次の季節でしょうか?: %t 。\n", w.Ja(), a.Ja(), w.IsNextOf(enum.Autumn))
}
package enum
import "strings"
type Season int
// enum の本体。実体は iota による int 値なのはよくあるそのまま。 [1]
const (
Unknown Season = iota
Spring
Summer
Autumn
Winter
)
func (s Season) Ja() string { return s.get().Ja } // 日本語表記文字列を返す
func (s Season) En() string { return s.get().En } // 英語表記文字列を返す
func (s Season) Next() Season { return s.get().Next } // 次の季節を返す
func (s Season) Prev() Season { return s.get().Prev } // 前の季節を返す
func (s Season) IsNextOf(other Season) bool { return s.Prev() == other } // 次の季節かどうかを判定
func (s Season) IsPrevOf(other Season) bool { return s.Next() == other } // 前の季節かどうかを判定
func (s Season) String() string { return s.Ja() } // ログ出力を考慮して String() も実装しておく
// 文字列表現などから enum を生成する関数。ウェブ開発などでビュー層からもらった文字列から作りたいときによく使う。
func SeasonValueOf(s string) Season { // hash lookup is more suitable than linear search?
for _, season := range seasons {
if strings.EqualFold(s, season.En) || s == season.Ja {
return season.V
}
}
return Unknown
}
// Season enum の多様な属性(情報)を表現する構造体の型
type attr struct {
V Season
Ja string
En string
Next Season
Prev Season
}
// enum の値に応じた属性(情報)を実際に定義している。 [2]
var seasons = [cnt]attr{
{Unknown, "未定義", "unknown", Unknown, Unknown},
{Spring, "春", "Spring", Summer, Winter},
{Summer, "夏", "Summer", Autumn, Spring},
{Autumn, "秋", "Autumn", Winter, Summer},
{Winter, "冬", "Winter", Spring, Autumn},
}
// enum のバリエーション数。これを定数化し [2] と [3]  の両方に使っているのがみそだと思っている。
// enum が拡張されて [1] や [2] のバリエーション数が増えた場合、この cnt も変更され、 [3] の境界条件判定も自動で更新される。
const cnt = 5
// enum 値から属性情報をひっぱってくるメソッド。ここでありえない enum 値を制御できる。 [3]
func (s Season) get() attr {
if s < 0 || s >= cnt {
return seasons[0] // or panic("Illegal enum value.")
}
return seasons[s]
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment