Go ポインタを含むプロジェクトで興味深い問題が発生しました。問題は、構造体オブジェクトのスライスをインターフェイスのスライスに変換するときに、最初のポインターのメモリ アドレスが出力で繰り返し使用されることでした。
この問題を解決するために、開発者は追加の関数を使用するように変換関数を変更しました。
これにより、元のソリューションがなぜ失敗したのかという疑問が生じます。これを理解するには、Go がポインターとスライスをどのように処理するかを詳しく調べる必要があります。
Go では、式 *coll は、基になる配列、その長さ、およびその容量に関する情報を含むスライス ヘッダーを返します。スライスの要素にアクセスする場合、式 (*coll)[idx] が使用され、インデックス idx の要素への参照が返されます。
元のソリューションでは、 item は範囲内のループ変数でした。 *コールループ。このループはスライス ヘッダーを反復処理し、スライスの各要素をループ変数項目に割り当てます。ただし、item はループ変数であるため、そのメモリ アドレスはループ全体を通じて同じままです。したがって、&item が出力スライスに追加されると、同じメモリ アドレスが複数回追加され、観察された動作が発生します。
修正されたソリューションでは、式 i := (*coll)[idx] を内で使用します。ループして、インデックス idx の要素をローカル変数 i に割り当てます。この変数にはループ変数項目とは異なるメモリ アドレスがあるため、&i が出力スライスに追加されると、各要素は異なるメモリ アドレスを持ちます。
ループ変数間のメモリ アドレスの違いを説明するには
package main import "fmt" func main() { coll := []int{5, 10, 15} for i, v := range coll { fmt.Printf("This one is always the same; %v\n", &v) fmt.Println("This one is 4 bytes larger each iteration; %v\n", &coll[i]) } }
このコードを実行すると、ループのすべての反復で &v が同じメモリ アドレスを持っていることがわかります。 &coll[i] には反復ごとに異なるメモリ アドレスがあります。
以上がGo の直接スライス変換がポインタに同じメモリ アドレスを再利用するのはなぜですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。