よくあるやつ
simpleSeason.go
package enum
type SimpleSeason int
const (
_ SimpleSeason = iota
Spring
Summer
Autumn
Winter
)
var simpleSeasonStrings = [4]string{"未定義", "春", "夏", "秋", "冬"}
func (s SimpleSeason) String() string {
return simpleSeasonStrings[s]
}
main.go
package main
import (
"fmt"
"github.com/ikngtty/playground/enum"
)
func main() {
fmt.Println(enum.Summer) // -> 夏
}
問題点
main.go
func printSeason(s enum.SimpleSeason) {
fmt.Println(s)
}
func main() {
// enum.Autumnじゃなくても無理やりautumnを作れてしまう
var autumn enum.SimpleSeason = 3
// 0〜4以外のありえない値を入れられる
printSeason(64) // runtime error: index out of range
}
simpleSeason.go
var simpleSeasonStrings = [5]string{"未定義", "春", "夏", "秋", "冬"}
func (s SimpleSeason) String() string {
// なので、SimpleSeasonを扱うときは必ずありえない値が来る可能性を
// 考慮しないといけない。
if s < 0 || s > 4 {
return "お前そういうことすんのやめろよマジで。"
}
return simpleSeasonStrings[s]
}
ぼくの考えたすごいやつ
season.go
package enum
type Season struct{ value string }
var Spring = Season{"春"}
var Summer = Season{"夏"}
var Autumn = Season{"秋"}
var Winter = Season{"冬"}
// String()をわざわざ定義しなくても {春} とか出るので十分わかりやすい
func (s Season) String() string {
if s.value == "" {
return "未定義"
}
return s.value
}
main.go
package main
import (
"fmt"
"github.com/ikngtty/playground/enum"
)
func main() {
fmt.Println(enum.Winter) // -> 冬
// パッケージの外からは、enum.Spring〜enum.Winterを使わない限り、
// ゼロ値しか作ることができない。
mySeason := enum.Season{}
fmt.Println(mySeason) // -> 未定義
}
フィールドを小文字にしてアクセス制限するのがポイント。
欠点を見つけた方は教えてください。
おまけ:列挙値の変数名が被る件
enum毎にいちいちpackage切りたくない時。
構造体を名前空間代わりにできそうです。
variousEnums.go
package enum
type ProgrammingLang struct{ value string }
var ProgrammingLangs = struct {
Perl ProgrammingLang
Ruby ProgrammingLang
Python ProgrammingLang
}{
Perl: ProgrammingLang{"Perl"},
Ruby: ProgrammingLang{"Ruby"},
Python: ProgrammingLang{"Python"},
}
type Jewelry struct{ value string }
var Jewelries = struct {
Perl Jewelry
Ruby Jewelry
Garnet Jewelry
}{
Perl: Jewelry{"Perl"},
Ruby: Jewelry{"Ruby"},
Garnet: Jewelry{"Garnet"},
}
main.go
package main
import (
"fmt"
"github.com/ikngtty/playground/enum"
)
func main() {
fmt.Println(enum.ProgrammingLangs.Ruby) // -> {Ruby}
fmt.Println(enum.Jewelries.Ruby) // -> {Ruby}
}