Go でジェネリック関数を作成する場合、具象型も受け入れると有益な場合があります。ただし、これらの特定の型の新しいインスタンスを使用してインターフェイスのスライスを初期化しようとすると、問題が発生します。
1 つのアプローチは論理的であるように思えるかもしれません。2 つの型パラメーターを定義することです。 1 つはスライス要素タイプ (X) 用で、もう 1 つはインスタンス化する具象タイプ (Y) 用です。ただし、このアプローチは、Y のインスタンスを X 型の要素に割り当てようとすると失敗します。
func Fill[X, Y any](slice []X){
for i := range slice {
slice[i] = new(Y) // not work!
}
}
この問題は、コンパイラがインターフェイス X とその実装 Y の間の関係を失うために発生します。X と Y は両方とも別個の任意の型として扱われます。
これに対処するには、関数内で明示的なキャスト操作を使用できます:
func Fill[X, Y any](slice []X) {
for i := range slice {
slice[i] = any(*new(Y)).(X)
}
}
ただし、このアプローチでは、Y が X を実装していない場合にパニックが発生します。これは、*sync.Mutex (ポインター型) を sync.Locker.
より堅牢でタイプセーフなソリューションには、コンストラクター関数の利用が含まれます:
func Fill[X any](slice []X, f func() X) {
for i := range slice {
slice[i] = f()
}
}
この関数は、指定された型の新しいインスタンスを返すコンストラクター関数を受け入れます。これにより、具象型インスタンスを使用したスライスの簡潔かつ安全な初期化が可能になります。
具象型をポインター型でインスタンス化する場合は、次の点に注意することが重要です。 new(Y) は nil 値になります。これを回避するには、func() X { return &sync.Mutex{} }.
など、正しいポインター値を返すようにコンストラクター関数を調整できます。免責事項: 提供されるすべてのリソースの一部はインターネットからのものです。お客様の著作権またはその他の権利および利益の侵害がある場合は、詳細な理由を説明し、著作権または権利および利益の証拠を提出して、電子メール [email protected] に送信してください。 できるだけ早く対応させていただきます。
Copyright© 2022 湘ICP备2022001581号-3