Code Fix

上級

スライスやマップを含む構造体は == で比較できない

スライスやマップ、関数値をフィールドに持つ構造体は比較不可能な型として扱われ、==演算子で比較しようとするとコンパイルエラーになります。

エラーメッセージの読み方

./main.go:12:14: invalid operation: a == b (struct containing []int cannot be compared)
./main.go
ファイル名
12
行番号
14
列番号
invalid operation: a == b (struct containing []int cannot be compared)
詳細メッセージ — 何が問題だったか

このエラーが出る典型パターン

パターン1

 1  package main
 2  
 3  import "fmt"
 4  
 5  type Box struct {
 6  	Items []int
 7  }
 8  
 9  func main() {
10  	a := Box{Items: []int{1}}
11  	b := Box{Items: []int{1}}
12  	fmt.Println(a == b                      )
                               ^
13  }
./main.go:12:14: invalid operation: a == b (struct containing []int cannot be compared)

Itemsフィールドがスライスのため、Box型全体を==で比較することはできません。フィールドごとに比較するか、reflect.DeepEqualを使う必要があります。

直し方: a == blen(a.Items) == len(b.Items) にします。

この問題を解いてみる →

広告
広告スロット(未設定)

パターン2

 1  package main
 2  
 3  import "fmt"
 4  
 5  type Cart struct {
 6  	Tags []string
 7  }
 8  
 9  func main() {
10  	a := Cart{Tags: []string{"go"}}
11  	b := Cart{Tags: []string{"go"}}
12  	fmt.Println(a == b                    )
                              ^
13  }
./main.go:12:14: invalid operation: a == b (struct containing []string cannot be compared)

[]stringも比較不能な型のひとつで、同様に構造体全体の==比較を妨げます。

直し方: a == blen(a.Tags) == len(b.Tags) にします。

この問題を解いてみる →

パターン3

 1  package main
 2  
 3  import "fmt"
 4  
 5  type Config struct {
 6  	Options map[string]bool
 7  }
 8  
 9  func main() {
10  	a := Config{Options: map[string]bool{"x": true}}
11  	b := Config{Options: map[string]bool{"x": true}}
12  	fmt.Println(a == b                          )
                                 ^
13  }
./main.go:12:14: invalid operation: a == b (struct containing map[string]bool cannot be compared)

マップもスライスと同様に比較演算子を持たない型で、含む構造体全体の比較を不可能にします。

直し方: a == blen(a.Options) == len(b.Options) にします。

この問題を解いてみる →

パターン4

 1  package main
 2  
 3  import "fmt"
 4  
 5  type Team struct {
 6  	Members []string
 7  }
 8  
 9  func main() {
10  	a := Team{Members: []string{"a", "b"}}
11  	b := Team{Members: []string{"a", "b"}}
12  	fmt.Println(a == b                          )
                                 ^
13  }
./main.go:12:14: invalid operation: a == b (struct containing []string cannot be compared)

すべてのフィールドが比較可能な型であることが==成立の前提で、1つでもスライスがあれば崩れます。

直し方: a == blen(a.Members) == len(b.Members) にします。

この問題を解いてみる →

パターン5

 1  package main
 2  
 3  import "fmt"
 4  
 5  type Playlist struct {
 6  	Songs []int
 7  }
 8  
 9  func main() {
10  	a := Playlist{Songs: []int{1, 2}}
11  	b := Playlist{Songs: []int{1, 2}}
12  	fmt.Println(a == b                      )
                               ^
13  }
./main.go:12:14: invalid operation: a == b (struct containing []int cannot be compared)

内容が本当に一致しているか比べたい場合は、reflect.DeepEqualやフィールドごとの比較関数を自分で書く必要があります。

直し方: a == blen(a.Songs) == len(b.Songs) にします。

この問題を解いてみる →

よくある誤解

「構造体同士の==は、フィールドを1つずつ再帰的に比較してくれるはず」という思い込みは誤りです。==による比較はすべてのフィールドが比較可能な型であることが前提で、スライスやマップのように比較演算子を持たない型が1つでもあるとコンパイルできません。

まとめ

スライスやマップを含む構造体は == で比較できないは上級でつまずきやすい項目です。上の5パターンを実際に手で直すと、エラーメッセージのどこを読めばよいかが掴めます。

演習をはじめる

関連するエラー

広告
広告スロット(未設定)