やりたいこと
struct内に埋め込んだmapのfieldの値を上書きするという処理を考えます。
下記のようなサンプルコードがあったときに originalSamples
のItemsの中身を上書きするような処理です。
type Samples struct { Items map[string]string } originalSamples := Samples{ Items: map[string]string{ "first": "apple", "second": "orange", }, }
やることはmapの中身を更新するだけなのですが、いくつかハマったのでメモとして残して起きます。
ハマったところ
assignment to entry in nil map
が発生した
mapを初期化しなかったケースです。
mapを初期化せずに新規の値をappendしようとすると panic: assignment to entry in nil map
のエラーが発生します。
var m Samples for k, item := range originalSamples.Items{ item = "iPhone" m.Items[k] = item }
この場合は var で定義するのではなく Sample{}
で初期化することが必要になります。
structを初期化してもassinment to entry in nil map
が起きた
structを初期化しても同様のエラーが発生しました。
具体的なコードは以下です。
originalSamples := Samples{ Items: map[string]string{ "first": "pc", "second": "book", }, } m := Samples{} for k, item := range originalSamples.Items { item = "iPhone" m.Items[k] = item }
これはなぜ起きるかというと、struct内に埋め込まれているmapはstructをインスタンス化してもnilでになってしまうために assignment to entry in nil map
のエラーが発生します。
こちらを回避策を検討した結果、mapをnilしないようにするので下記の2パターンが考えられると思います。
- mapをinstace化して後で上書きしたいstructに代入する
- structのinstance化と合わせて埋め込まれているmapもinstance化する
// mapをinstance化する newSamples := Samples{} m := make(map[string]string) for k, item := range originalSamples.Items { item = "iPhone" m[k] = item } // structに代入する newSamples.Items = m fmt.Printf("%v", newSamples)
// structのinstance化のタイミングでmapも初期化する newSamples := Samples{ Items: map[string]string{}, } for k, item := range originalSamples.Items { item = "iPhone" newSamples.Items[k] = item } fmt.Printf("%v", newSamples)
まとめ
mapを動的に扱いたい場合は、ちゃんと初期化されているか確認する。
structを初期化しても中のpropertyまで初期化されているわけではない。