Go言語楽しいですね。
でも、やっぱりポインタ周りでつまずく事になりました。
マップに入れた構造体が変更できなくて
困っておりました。
valueの変更ができない
personMap := map[int]Person{}
personMap[1] = Person{Id: 1, Name: "aaa", Age: 20}
personMap[2] = Person{Id: 2, Name: "bbb", Age: 21}
personMap[3] = Person{Id: 3, Name: "ccc", Age: 22}
person := personMap[1]
person.Age = 30 // ここで変更を反映させたい
pp.Printf(personMap)
上記のコード、マップに収められている構造体に対して、変更をかけたいんですが
実際には変更が反映されません。
map[int]main.Person{
1: main.Person{
Id: 1,
Name: "aaa",
Age: 20,
},
2: main.Person{
Id: 2,
Name: "bbb",
Age: 21,
},
3: main.Person{
Id: 3,
Name: "ccc",
Age: 22,
},
}
そりゃそうなんだろうね〜。
変更したい場合は、ポインタを取得して
アドレスに対して変更をかけないといけないんだけど…
valueのアドレスアクセスは禁止されている
person := &personMap[1] // ここでエラー
person.Age = 30
とできるのかと思いきや、これは出来ないみたいです。
ではでは、直接変更できないもんかねと思うんですが、これもダメみたい。
personMap[1].Age = 30 // これもエラー
cannot assign to struct field personMap[1].Age in map
というエラーがでます。
ダイレクトアクセスがダメな理由
マップ構造は、要素の追加により
アドレス空間を再構築するため、
収められている構造体のアドレスも
途中で変更されるみたいです。
ポインタの場合は、
収められている値は再構築されても、
ポインタ自体の値は変更されないので、
問題ないってことです。
構造体ポインタのmapにしよう
じゃあどうするのか?
構造体のmapを作るときは
構造体のポインタを要素として持たせると良いみたいです。
personMap := map[int]*Person{} // ポインタのmapに
personMap[1] = &Person{Id: 1, Name: "aaa", Age: 20} // 構造体のポインタを格納する
personMap[2] = &Person{Id: 2, Name: "bbb", Age: 21}
personMap[3] = &Person{Id: 3, Name: "ccc", Age: 22}
person := personMap[1]
person.Age = 30
pp.Println(personMap)
map[int]*main.Person{
1: &main.Person{
Id: 1,
Name: "aaa",
Age: 30,
},
2: &main.Person{
Id: 2,
Name: "bbb",
Age: 21,
},
3: &main.Person{
Id: 3,
Name: "ccc",
Age: 22,
},
}
ちゃんと、aaaさんのAgeが更新されている事がわかります。
ポインタのmapにしておかないと、取り出すたびに構造体のコピーが生成されているという事なんでしょうね。
おしまい
personMap := map[int]Person{}
personMap := map[int]*Person{}
json::Unmarshal に渡すときは、&personMap という形で渡しますが、
要素が 構造体であろうが、ポインタであろうが正常に動作するようです。
json.Unmarshal(bytes, &personMap)
1件のコメント