45
22

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

GoでEnumを定義する 〜intやstringよりも厳密に〜

Last updated at Posted at 2019-01-04

よくあるやつ

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}
}
45
22
2

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
45
22

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?