exhaustruct

Table of Contents

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

exhaustruct は構造体のすべてのフィールドが初期化されているかをチェックするツールです。

解決する問題

構造体の初期化時にフィールドを省略すると、ゼロ値が暗黙的に設定されます。新しいフィールドが追加された際に初期化漏れが発生しやすく、意図しないデフォルト値によるバグの原因になります。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// Before: フィールドの初期化漏れ
type DBConfig struct {
Host string
Port int
User string
Password string
SSLMode string
}

func NewDBConfig() DBConfig {
return DBConfig{
Host: "localhost",
Port: 5432,
// User, Password, SSLMode が未設定 → ゼロ値(空文字列)
}
}
1
2
3
4
5
6
7
8
9
10
// After: すべてのフィールドを明示的に初期化
func NewDBConfig() DBConfig {
return DBConfig{
Host: "localhost",
Port: 5432,
User: "app",
Password: "",
SSLMode: "disable",
}
}

設定

公式ドキュメント

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

linters:
enable:
- exhaustruct
settings:
exhaustruct:
include:
- '.*Config$'
- '.*Options$'
exclude:
- 'net/http\.Client'

オプション

オプション デフォルト 説明
include []string [] チェック対象の型名の正規表現リスト(パッケージパスを含むフルネームでマッチ)
exclude []string [] チェック除外の型名の正規表現リスト(include より優先)
allow-empty bool false 空の構造体リテラル(T{})をグローバルに許可する
allow-empty-returns bool false return 文での空の構造体リテラルを許可する
allow-empty-declarations bool false 変数宣言での空の構造体リテラルを許可する
allow-empty-rx []string [] 空の構造体リテラルを許可する型名の正規表現リスト

include / exclude の使い分け

1
2
3
4
5
6
7
8
9
10
11
linters:
settings:
exhaustruct:
# Config と Options で終わる型のみチェック
include:
- '.*Config$'
- '.*Options$'
# 外部パッケージの型はチェック対象外
exclude:
- 'net/http\..*'
- 'google\.golang\.org/.*'

サンプル

検出例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// exhaustruct が警告するパターン

type ServerConfig struct {
Host string
Port int
ReadTimeout time.Duration
WriteTimeout time.Duration
MaxBodySize int64
}

// 1. フィールド不足
func NewServer() ServerConfig {
return ServerConfig{
Host: "0.0.0.0",
Port: 8080,
// exhaustruct: ServerConfig is missing fields: ReadTimeout, WriteTimeout, MaxBodySize
}
}

// 2. 空の構造体リテラル(allow-empty: false の場合)
func DefaultConfig() ServerConfig {
return ServerConfig{} // exhaustruct: ServerConfig is missing all fields
}

修正例

1
2
3
4
5
6
7
8
9
func NewServer() ServerConfig {
return ServerConfig{
Host: "0.0.0.0",
Port: 8080,
ReadTimeout: 30 * time.Second,
WriteTimeout: 30 * time.Second,
MaxBodySize: 1 << 20, // 1MB
}
}

注意点

  • include を指定しない場合、すべての構造体がチェック対象になる。プロジェクト全体に適用すると外部ライブラリの型でも警告が出るため、include で対象を絞るのが推奨
  • excludeinclude より優先される。外部パッケージの型を除外したい場合に使用する
  • //exhaustruct:enforce ディレクティブをコードに付与すると、グローバル設定で除外されていてもその構造体を強制チェックできる
  • allow-empty-returns: true にすると、エラー時の return Config{}, err パターンを許容できる
  • テストコードでは allow-empty-declarations: true にすると、テスト用の空構造体宣言を許容できる

参考リンク