Go 1.18 ジェネリックの反変型
Go 1.18 では、ジェネリックの導入により、反変型への関心が高まりました。生じる重要な問題は、ジェネリックのコンテキスト内でジェネリックがどのように機能するかということです。
好ましくない動作: 互換性のない型
次のコード スニペットを考えてみましょう:
func Pipe[A, T1, T2 any](left func(A) T1, right func(T1) T2) func(A) T2 { return func(a A) T2 { return right(left(a)) } }
次の関数で Pipe を使用しようとすると:
func OpenFile(name string) *os.File { ... } func ReadAll(rdr io.Reader) []byte { ... }
コンパイラは T1 を io.Reader と同一ではない *os.File として扱うため、コンパイルは失敗します。
根本原因: 反変セマンティクス
この問題は、反変型の性質に起因します。この場合、T1 は A よりも具体的な型であることが期待されます。つまり、T1 を受け入れる関数は A も受け入れることができます。ただし、Go ジェネリックは共変の結果型をサポートしません。したがって、T1 を返す関数は、たとえ暗黙的に変換可能であっても、A を返すことはできません。
解決と結果
現時点では、Pipe の署名を変更する方法はありません。目的の動作を可能にするために 1.18 に進みます。これはバグではなく、意図的な設計上の選択であると考えられます。
回避策: 型変換
この制限を回避するには、実行時に型変換を行うことができます。
func Pipe[A, T1, T2, T3 any](left func(A) T1, right func(T2) T3) func(A) T3 { return func(a A) T3 { return right(any(left(a)).(T2)) } }
ただし、このアプローチではコンパイル時の型安全性が犠牲になります。
以上が反変型は Go 1.18 ジェネリックでどのように機能しますか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。