exhaustive

Table of Contents

  1. 解決する問題
  2. 設定
  3. オプション
  4. サンプル
    1. 検出例
    2. 修正例
  5. 注意点
  6. 参考リンク

exhaustive は enum(定数グループ)に対する switch 文や map リテラルの網羅性をチェックするツールです。

解決する問題

Go の switch 文は、enum のすべてのケースを列挙しなくてもコンパイルが通ります。新しい enum メンバーを追加した際に、対応する switch 文の更新を忘れると実行時に想定外の挙動を引き起こします。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// Before: Pending を追加したが switch 文を更新し忘れた
type Status int

const (
_ Status = iota
StatusActive
StatusInactive
StatusPending // 新しく追加
)

func HandleStatus(s Status) string {
switch s {
case StatusActive:
return "active"
case StatusInactive:
return "inactive"
// StatusPending のケースがない → コンパイルは通るが実行時に空文字列を返す
}
return ""
}
1
2
3
4
5
6
7
8
9
10
11
12
// After: exhaustive の警告に従いすべてのケースを網羅
func HandleStatus(s Status) string {
switch s {
case StatusActive:
return "active"
case StatusInactive:
return "inactive"
case StatusPending:
return "pending"
}
return ""
}

設定

公式ドキュメント

1
2
3
4
5
6
7
8
9
10
11
12
# .golangci.yml 設定例
version: "2"

linters:
enable:
- exhaustive
settings:
exhaustive:
check:
- switch
- map
default-signifies-exhaustive: false

オプション

オプション デフォルト 説明
check []string [switch] チェック対象。switchmap を指定可能
default-signifies-exhaustive bool false default ケースがあれば網羅的とみなす
default-case-required bool false 網羅的であっても default ケースを必須にする
ignore-enum-members string "" 指定した正規表現にマッチする enum メンバーをチェック対象外にする
ignore-enum-types string "" 指定した正規表現にマッチする enum 型をチェック対象外にする
package-scope-only bool false パッケージスコープの enum のみをチェック対象にする
explicit-exhaustive-switch bool false //exhaustive:enforce コメント付きの switch のみチェックする
explicit-exhaustive-map bool false //exhaustive:enforce コメント付きの map のみチェックする

サンプル

検出例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
type Role int

const (
_ Role = iota
RoleAdmin
RoleEditor
RoleViewer
)

// exhaustive が警告: missing cases in switch of Role: RoleViewer
func Describe(r Role) string {
switch r {
case RoleAdmin:
return "administrator"
case RoleEditor:
return "editor"
// RoleViewer が漏れている
}
return "unknown"
}

// map リテラルのチェック(check に "map" を追加した場合)
// exhaustive が警告: missing keys in map of Role: RoleViewer
var roleNames = map[Role]string{
RoleAdmin: "Admin",
RoleEditor: "Editor",
// RoleViewer が漏れている
}

修正例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
func Describe(r Role) string {
switch r {
case RoleAdmin:
return "administrator"
case RoleEditor:
return "editor"
case RoleViewer:
return "viewer"
}
return "unknown"
}

var roleNames = map[Role]string{
RoleAdmin: "Admin",
RoleEditor: "Editor",
RoleViewer: "Viewer",
}

注意点

  • default-signifies-exhaustive: true にすると default ケースがある switch は警告されなくなる。網羅性を厳密に保ちたい場合は false(デフォルト)のままにする
  • explicit-exhaustive-switch: true にすると、//exhaustive:enforce コメントが付いた switch のみがチェック対象になる。段階的に導入したい場合に便利
  • iota で定義された定数グループが対象。単独の const 定義は enum として認識されない
  • 外部パッケージの enum も検出対象になるため、ignore-enum-types で制御できる

参考リンク