0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Goでenumを評価するswitch文を使うときはあえてdefaultを指定しないことで楽になる

Last updated at Posted at 2024-12-06

なぜ楽になるか?

enumで定義した全ての要素をswitch文で考慮しているかlinterがチェックしてくれるから。

具体例

こんなenumを想定する。

type Item uint8

const (
	itemA Item = iota
	itemB
	itemC
)

例えば、アプリケーションで定義している型をDBに入れる値として変換したいときなど、何かしら変換をしたいことがある。すると、以下のような関数を書きがち。


func convertItemToString(i Item) (string, error) {
	switch i {
	case itemA:
		return "itemA", nil
	case itemB:
		return "itemB", nil
	case itemC:
		return "itemC", nil
	default:
		return "", fmt.Errorf("invalid item.")
	}
}

ここで、以下のように新たにitemDを追加する。itemDは"itemD"としてマッピングしたいものとする。

const (
    itemA Item = iota
    itemB 
    itemC 
    itemD 
)

ただ、うっかりするとconvertItemToStringにitemDのcaseを追加するのを忘れてエラーを起こしてしまう。

そこで、以下のようにあえてdefaultを外して書く。


func convertItemToString(i Item) (string, error) {
    switch i {
        case itemA:
            return "itemA", nil
        case itemB:
            return "itemB", nil
        case itemC:
            return "itemC", nil
    } 
    return "", fmt.Errorf("invalid item.")
}

すると、exhaustiveというlinterがitemDのcaseがないことを検知してくれる。ちなみにexhaustiveはgolangci-lintに組み込まれている。

以下のようにlinterを設定

.golangci.yml
linters:
  enable:
    - exhaustive

こんな感じでlint errorになる
main.go:15:2: missing cases in switch of type main.Item: main.itemD (exhaustive)
        switch i {
        ^

convertItemToStringのような関数でテストを書こうとすると、単調な関数な割には項目が増えるたびにテストをメンテしなければならず面倒になる。しかし、switch文にdefaultを入れないことでlinterがバグの原因を未然に検知してくれるので、対象の関数が十分に簡単であればメンテコストを加味してテストを書かないという選択肢も取れる。

ここでitemDのケースを追加すればlintエラーは消える

func convertItemToString(i Item) (string, error) {
    switch i {
        case itemA:
            return "itemA", nil
        case itemB:
            return "itemB", nil
        case itemC:
            return "itemC", nil
        case itemD:
            return "itemD", nil
    } 
    return "", fmt.Errorf("invalid item.")
}

ちなみにdefaultで何もしなくても同じようにlintエラーになる

func convertItemToString(i Item) (string, error) {
	switch i {
	case itemA:
		return "itemA", nil
	case itemB:
		return "itemB", nil
	case itemC:
		return "itemC", nil
	default:
	}
	return "", fmt.Errorf("invalid item.")
}
やはりlint error
main.go:15:2: missing cases in switch of type main.Item: main.itemD (exhaustive)
        switch i {
0
0
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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?