Code Fix

上級

does not satisfy(ジェネリクスの制約違反)の原因と直し方

ジェネリック関数の型パラメータには制約(constraint)を指定できます。制約が要求する演算(比較や算術演算など)をサポートしない型を渡すと、コンパイルエラーになります。

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

./main.go:18:17: string does not satisfy Number (string missing in ~int | ~float64)
./main.go
ファイル名
18
行番号
17
列番号
string does not satisfy Number (string missing in ~int | ~float64)
詳細メッセージ — 何が問題だったか

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

パターン1

 1  package main
 2  
 3  import "fmt"
 4  
 5  type Number interface {
 6  	~int | ~float64
 7  }
 8  
 9  func sum[T Number](vals []T) T {
10  	var total T
11  	for _, v := range vals {
12  		total += v
13  	}
14  	return total
15  }
16  
17  func main() {
18  	fmt.Println(sum([]string{"a", "b"} ))
                              ^
19  }
./main.go:18:17: string does not satisfy Number (string missing in ~int | ~float64)

Number制約はintかfloat64系の型しか許しません。stringは加算演算子+=に対応していないため、コンパイルエラーになります。

直し方: []string{"a", "b"}[]int{1, 2} にします。

この問題を解いてみる →

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

パターン2

 1  package main
 2  
 3  import "fmt"
 4  
 5  type Number interface {
 6  	~int | ~float64
 7  }
 8  
 9  func sum[T Number](vals []T) T {
10  	var total T
11  	for _, v := range vals {
12  		total += v
13  	}
14  	return total
15  }
16  
17  func main() {
18  	fmt.Println(sum([]bool{true, false}))
                              ^
19  }
./main.go:18:17: bool does not satisfy Number (bool missing in ~int | ~float64)

boolは+=のような算術演算をサポートしないため、Number制約を満たせずコンパイルエラーになります。

直し方: []bool{true, false}[]float64{1.5, 2.5} にします。

この問題を解いてみる →

パターン3

 1  package main
 2  
 3  import "fmt"
 4  
 5  type Number interface {
 6  	~int | ~float64
 7  }
 8  
 9  func sum[T Number](vals []T) T {
10  	var total T
11  	for _, v := range vals {
12  		total += v
13  	}
14  	return total
15  }
16  
17  func main() {
18  	fmt.Println(sum([]byte{1, 2}      ))
                              ^
19  }
./main.go:18:17: byte does not satisfy Number (byte missing in ~int | ~float64)

byteはuint8のエイリアスで、Number制約の~int | ~float64のどちらの基底型にも一致しないため弾かれます。

直し方: []byte{1, 2}[]int{3, 4} にします。

この問題を解いてみる →

パターン4

 1  package main
 2  
 3  import "fmt"
 4  
 5  type Number interface {
 6  	~int | ~float64
 7  }
 8  
 9  func sum[T Number](vals []T) T {
10  	var total T
11  	for _, v := range vals {
12  		total += v
13  	}
14  	return total
15  }
16  
17  func main() {
18  	fmt.Println(sum([]rune{'a', 'b'}  ))
                              ^
19  }
./main.go:18:17: rune does not satisfy Number (rune missing in ~int | ~float64)実際はint32型として扱われる

runeはint32のエイリアスですが、制約が~intのように書かれていてもruneという別名の型自体は基底型がint32でありintではないため一致しません。

直し方: []rune{'a', 'b'}[]int{5, 6} にします。

この問題を解いてみる →

パターン5

 1  package main
 2  
 3  import "fmt"
 4  
 5  type Number interface {
 6  	~int | ~float64
 7  }
 8  
 9  func sum[T Number](vals []T) T {
10  	var total T
11  	for _, v := range vals {
12  		total += v
13  	}
14  	return total
15  }
16  
17  func main() {
18  	fmt.Println(sum([]complex64{1, 2} ))
                              ^
19  }
./main.go:18:17: complex64 does not satisfy Number (complex64 missing in ~int | ~float64)

複素数型complex64も~int | ~float64のどちらにも含まれないため、Number制約を満たせません。

直し方: []complex64{1, 2}[]int{7, 8} にします。

この問題を解いてみる →

よくある誤解

「anyを制約にしておけば、どんな型でも渡せてどんな演算もできるはず」という思い込みは誤りです。any(interface{})を制約にすると比較以外のほとんどの演算ができなくなるため、算術演算が必要な場合はconstraints.OrderedのようなAsc要求を満たす制約を指定する必要があります。

まとめ

does not satisfy(ジェネリクスの制約違反)の原因と直し方は上級でつまずきやすい項目です。上の5パターンを実際に手で直すと、エラーメッセージのどこを読めばよいかが掴めます。

演習をはじめる

関連するエラー

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