🙌
Go の Generics でできないこと
はじめに
Go 1.18 で導入された Generisc を試してみて色々と分かったことがあるのでまとめます。
そもそもの仕様が理解不足な面もありますが、とりあえず当たったパターンを書いていきます。
参考文献にも挙げた Go言語のジェネリクス入門(1) でおっしゃられているように、 Generics の基本原則を抑えておけば今回のような誤解は解けそうです。
- 「関数」と「型」は「型パラメータ」を持つことができる。
もし理解違いがありましたら教えて下さいませ〜🙏
環境
Go: 1.19.0
メソッドに型パラメータを持つことはできない
メソッドに型パラメータを持つことはできません。
型パラメータを持つメソッドの定義は可能です。
呼び出すことはできません。
(この後紹介する例のように厳密には異なるのですが、実運用としては上記の解釈で間違いありません)
type Value()
func (v *Value) method[T any]() {}
func main() {
v := &Value{}
// Invalid operation: 'v.method[string]' (type 'func[T any]()' does not support indexing)
// Type 'string' is not an expression
v.method[string]()
}
あまり意味はないですが、型パラメータの指定を省略すれば呼び出しは可能です。
その場合は構文エラーにはなりません。
type Value()
func (v *Value) method[T any]() {}
func main() {
v := &Value{}
v.method()
}
解決策としては、レシーバを受け取らない素の関数にすることです。
func method[T any]() {}
func main() {
method[string]()
}
型パラメータを持つ関数型の DefinedType で、右辺で型パラメータを利用することはできない
型パラメータを持つ関数型の DefinedType で、右辺で型パラメータを利用することはできません。
表現がややこしいですが、以下の例では保持した型パラメータを DefinedType の引数の型として利用しています。
(上手い表現もしくは、definedType の右辺を表す固有名詞があれば教えて下さい!)
type funcType[T any] = func(arg T)
func main(f funcType[string]) {
// Cannot call the nonfunction f that has the type funcType[string]
f("str")
}
DeifnedType の引数の型ではなく、戻り値の型として利用した場合も同様です。
type funcType[T any] = func() T
func main(f funcType[string]) {
// Cannot call the nonfunction f that has the type funcType[string]
str := f()
}
解決策としては、関数自体で型パラメータを受け取り、関数型をインラインで直接定義すれば呼び出すことが可能です。
(あまり解決策とは呼べませんが、、、)
func main[T any](t T, f func(arg T) ) {
f(t)
}
まとめ
良き Go ライフを過ごしましょう!!
Discussion