Go では、スライスとマップは参照型であるという特徴を共有します。ただし、パラメータに新しい要素を追加する場合の動作は異なります。マップに追加された新しい要素は引数に自動的に反映されますが、スライスに追加された新しい要素は引数で「破棄」されます。
この矛盾は、これらの型の実装方法に起因します。マップは、内部ハッシュ マップ データ構造へのポインターとして実装されます。新しい要素がマップに追加されると、ハッシュ マップ データ構造は更新されますが、基礎となるポインターは変更されません。これにより、マップへのすべての参照が同じ基礎となるデータ構造を指すことが保証されます。一方、
スライスは、スライスの長さと容量とともにバッキング配列へのポインターを格納する構造体として実装されます。新しい要素がスライスに追加されると、更新された長さで新しいスライス ヘッダーを作成する必要があり、必要に応じて新しいバッキング配列も作成する必要があります。この新しいスライス ヘッダーは、それを指す変数に割り当てられますが、元のスライス ヘッダーは変更されません。
観察された動作に寄与するもう 1 つの要因は、Go の値による受け渡しです。セマンティクス。マップが関数に渡されると、関数はマップ ポインターのコピーを受け取ります。このコピーを通じてマップに加えられた変更は、元のマップにも影響します。これは、どちらも同じ基礎となるデータ構造を指しているためです。
スライスが関数に渡されると、関数はスライス ヘッダーのコピーを受け取ります。 。スライスを変更すると、長さと容量が更新された新しいスライス ヘッダーが作成されますが、元のスライス ヘッダーは影響を受けません。その結果、引数には関数内で行われた変更が表示されません。
このコンテキストにおけるスライスとマップの動作の違いは、開発者にとって潜在的な落とし穴につながる可能性があります。特に Go を初めて使用する人。これらの参照型の API は、一方は値の変更に対して期待どおりに動作するが、もう一方は期待どおりに動作しないため、一貫性がないように見えます。
API 動作の一貫性を実現するには、スライスを次のように動作させることができます。マップと同様に、基礎となるデータ構造へのポインター。ただし、このアプローチはほとんど使用されず、言語サポートがありません。代わりに、要素を追加するときに新しいスライスを返すのが一般的です。これにより、呼び出し元はスライスの更新されたバージョンを確実に受け取ります。
以上が要素を関数パラメータとして追加すると、Go のスライスとマップの動作が異なるのはなぜですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。