Programmingバックエンド開発者

Goは、mapやsliceを関数に渡す際に、メモリの管理をどのように実装し、それが何に繋がる可能性があるのか教えてください。

Hintsage AIアシスタントで面接を突破

答え。

Goでは、mapの構造は常に値渡しされますが、その値はmapの内部構造(内部的にはハッシュテーブル)へのポインタを含んでいます。したがって、関数にmapを渡し、その関数内で内容を変更(要素を追加/削除)すると、変更は外部からも確認できます。sliceも同様に振る舞い、sliceの構造はコピーされますが、データの配列自体はコピーされません。sliceは配列へのポインタ、長さ、容量を含んでいます。関数内でインデックスによる値の変更を行うと、元の配列も変更されます。しかし、関数内で新しいsliceを割り当てた場合(例えば、reslice)、元の変数は変更されません。

func updateMap(m map[string]int) { m["key"] = 42 // 変更は外部からも見える! } func updateSlice(s []int) { s[0] = 99 // 元の配列が変更される }

トリッキーな質問。

なぜmapやsliceを関数に渡すと、関数内での変更が「オリジナル」に反映されるのですか?

答え: ポインタの構造だけがコピーされ、実際のデータは共有されたままです — どんな変更も同じメモリブロックに影響を与えます。

問題の詳細に関する実際のエラーの例。


物語

fintechプロジェクトでは、設定用のmapを異なるサービスに渡し、ローカルの変更が共通のmapに影響しないと思っていました。その結果、一つのサービスが値を変更し、他のモジュールで予期しない変更された設定が原因でバグが発生しました。


物語

分析マイクロサービスでは、独立したコピーを取得することを期待してsliceを渡しましたが、関数内部でインデックスを通じて値を変更したため、元の配列が予期せず変更され、報告書のデータが歪んでしまいました。


物語

ゲームサーバーでは、ユーザーのセッションを保存するためにmapを使用し、このmapを複数のゴルーチンに渡しました。各ゴルーチンが自分のコピーで作業していると思われましたが、実際にはデータ競合が発生し、セッションが一部失われてしまいました。