ホームページ >バックエンド開発 >Golang >Golang ジェネリックスでインターフェイスのスライスを具体的な型で埋めるにはどうすればよいですか?

Golang ジェネリックスでインターフェイスのスライスを具体的な型で埋めるにはどうすればよいですか?

Barbara Streisand
Barbara Streisandオリジナル
2024-10-26 05:38:30540ブラウズ

How to Fill a Slice of Interfaces with Concrete Types in Golang Generics?

Golang ジェネリック: インターフェイスと具象型の同時使用

Go 1.18 では、ジェネリックにより型処理の新しい可能性が導入されました。ただし、特定のシナリオでは、インターフェイスと具象型を一緒に使用するときに問題が発生する可能性があります。

そのようなシナリオの 1 つは、次のような関数を作成しようとするときに発生します。

<code class="go">func Fill[X any](slice []*X){
   for i := range slice {
      slice[i] = new(X)
   }
}</code>

この関数は、具体的な型を使用したインターフェイスのスライス。たとえば、*int の配列は、この関数を使用して new(int) で埋めることができます。

この問題は、インターフェースを実装する具象型でインターフェースのスライスを埋めようとするときに発生します。次のコードを考えてみましょう:

<code class="go">func Fill[X, Y any](slice []X){
   for i := range slice {
      slice[i] = new(Y) // not work!
   }
}

xs := make([]sync.Locker, 10) // fill with nils
Fill[sync.Locker,sync.Mutex](xs) // ouch</code>

この場合、X と Y の両方を any に制約すると、インターフェイスと実装型の間の関係が壊れるため、関数は機能しません。コンパイラは、コンパイル時に X と Y が異なる型であることのみを認識します。

考えられる解決策

明示的なアサーションを使用してコードをコンパイルする回避策があります。

<code class="go">func Fill[X, Y any](slice []X) {
    for i := range slice {
        slice[i] = any(*new(Y)).(X)
    }
}</code>

ただし、この解決策には重大な欠点があります。sync.Locker や sync.Mutex のように、Y が X を実装していない場合にパニックが発生します。さらに、Y にポインター型を使用すると、基本型とゼロ値の情報が失われるため、結果は nil 値になります。

より良い代替手段

より堅牢な解決策は、代わりにコンストラクター関数を使用することです。 2 番目の型パラメーター:

<code class="go">func main() {
    xs := make([]sync.Locker, 10)
    Fill(xs, func() sync.Locker { return &sync.Mutex{} })
}

func Fill[X any](slice []X, f func() X) {
    for i := range slice {
        slice[i] = f()
    }
}</code>

このアプローチでは、関数は型 X のスライスとコンストラクター関数を受け取ります。コンストラクター関数は、型 X のインスタンスを作成し、スライスを具体的なインスタンスで埋めます。

以上がGolang ジェネリックスでインターフェイスのスライスを具体的な型で埋めるにはどうすればよいですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。