Go 1.18 の反変型のジェネリックス: 明確化と制限
Go 1.18 のジェネリックスを使用して、次の 2 つの関数を取る関数を定義する取り組み互換性はあるが同一ではない型、つまり反変的な動作は、課題に直面しています。その理由を理解するために詳細を掘り下げてみましょう。
次の関数定義について考えてみましょう。
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)) } }
この関数は、左側の関数の出力を右側の関数にパイプして計算を連鎖させることを目的としています。ただし、次の例で使用しようとすると、
func OpenFile(name string) *os.File { ... } func ReadAll(rdr io.Reader) []byte { ... } var OpenRead = Pipe(OpenFile, ReadAll)
コンパイルが失敗します。これは、io.Reader と互換性があるにもかかわらず、コンパイラーは T1 が *os.File と同一であると想定するためです。互換性のある型が受け入れられることを期待するのは合理的であるように思えるかもしれませんが、Go は共変結果型をサポートしていないため、そうではありません。
Go 1.18 でこの署名を修正する方法はありますか?
残念ながら、いいえ。 Go のジェネリックスには現在、型パラメータを使用して型の変換性を表現する機能が欠けているため、この動作を可能にするために Pipe 関数を変更することは不可能です。
これは Go 1.18 のバグですか?
いいえ。公式 FAQ に記載されているように、この動作は意図的なものであり、バグとはみなされません。
回避策
同様の結果を得るには、変換ステップを手動で実装できます。
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 サイトの他の関連記事を参照してください。