これからGO言語で構造体を使い倒さねばならない私(江端)が、これから何度でもハマるような気がするので、わざわざ簡単なプログラムを作って、今後の自分の為にメモを残す。
agents
スライスの要素を変更しても、その変更が反映されない理由として、agent
変数が値渡しである可能性があります。Goでは、スライスやマップなどのリファレンスタイプを使わない限り、変数は値渡しされます。
具体的には、以下のようなコードでは、agent
変数はスライスagents
の要素をコピーしたものであり、変更はagents
スライス自体には反映されません。
重要なポイントは、
"for i, agent := range agents {" は表示するだけなら問題はないが、書き込みはできず、
" for i := range agents {
agent := &agents[i] // この1行が滅茶苦茶重要"
としないと、書き込みが反映されない、ということであり、変更点は、以下のようにfor
ループ内でagent
をポインタとして扱うことである。
また表示の際にも、例えば1000番目の構造体のエージェントだけを表示したいのであれば、
i := 1000
if i < len(agents) { // これは構造体の数を越えていないかをチェックする
agent := &agents[i]
この1行が滅茶苦茶重要"
fmt.Printf("hh_id:%d idv_id:%d\n", agent.hh_id, agent.idv_id)
fmt.Printf("Agent %d: q1=%d, q2t=%d, q31=%d, q32=%d, q33=%d, q34=%d, q41a=%d, q42a=%d, q43a=%d, q44a=%d, q45a=%d, q46a=%d, q47a=%d, q41e=%d, q42e=%d, q43e=%d, q44e=%d, q45e=%d, q46e=%d, q47e=%d, q10=%d, q13=%d, q14=%d, no_answer=%d\n",
i, agent.q1, agent.q2t, agent.q31, agent.q32, agent.q33, agent.q34,
agent.q41a, agent.q42a, agent.q43a, agent.q44a, agent.q45a, agent.q46a, agent.q47a,
agent.q41e, agent.q42e, agent.q43e, agent.q44e, agent.q45e, agent.q46e, agent.q47e,
agent.q10, agent.q13, agent.q14, agent.no_answer)
for _, trip := range agent.trip {
fmt.Printf("trip: {id:%d act_id:%d trip_id:%d day:%d origin:%s destination:%s ox:%.6f oy:%.6f dx:%.6f dy:%.6f m_ox:%.6f m_oy:%.6f m_dx:%.6f m_dy:%.6f dep_area:%s arr_area:%s dep_time:%s m_dep_time:%s arr_time:%s m_arr_time:%s stay_time:%.2f traffic:%s next_id:%d category:%d}\n",
trip.id, trip.act_id, trip.trip_id, trip.day, trip.origin, trip.destination, trip.ox, trip.oy, trip.dx, trip.dy, trip.m_ox, trip.m_oy, trip.m_dx, trip.m_dy,
trip.dep_area, trip.arr_area, trip.dep_time.Format("15:04:05"), trip.m_dep_time.Format("15:04:05"), trip.arr_time.Format("15:04:05"), trip.m_arr_time.Format("15:04:05"), trip.stay_time.Hours(), trip.traffic, trip.next_id, trip.category)
}
以下は、その考え方を簡易に表現したもの
普通の構造体の取扱は、こんな感じでいい。
// G:\home\ebata\tomioka3B\src\others\main85.go
package main
import (
"errors"
"fmt"
)
// Trip構造体の定義
type Trip struct {
id int
act_id int
trip_id int
day int
}
// Agent構造体の定義
type Agent struct {
hh_id int
idv_id int
trip []Trip
sex int
no_answer int
}
// getGenderメソッドの定義
func (a Agent) getGender() (string, error) {
switch a.sex {
case 1:
return "女性", nil
case 2:
return "男性", nil
case 3:
return "その他(未回答)", nil
default:
return "", errors.New("invalid sex value")
}
}
func main() {
// エージェントを5個生成
agents := make([]Agent, 5)
for i := 0; i < 5; i++ {
agents[i] = Agent{
hh_id: i + 1,
idv_id: i + 1,
sex: (i % 3) + 1, // 1, 2, 3をループ
trip: []Trip{
{id: 1, act_id: 10, trip_id: 100 + i, day: 1},
{id: 2, act_id: 20, trip_id: 200 + i, day: 2},
},
}
}
// 各エージェントの性別とTrip情報を表示
for i, agent := range agents {
gender, err := agent.getGender()
if err != nil {
fmt.Printf("Agent %d: Error: %v\n", i+1, err)
} else {
fmt.Printf("Agent %d: Gender: %s\n", i+1, gender)
}
for _, trip := range agent.trip {
fmt.Printf("\tTrip ID: %d, Act ID: %d, Trip ID: %d, Day: %d\n", trip.id, trip.act_id, trip.trip_id, trip.day)
}
}
}
出力結果
$ go run main85.go
Agent 1: Gender: 女性
Trip ID: 1, Act ID: 10, Trip ID: 100, Day: 1
Trip ID: 2, Act ID: 20, Trip ID: 200, Day: 2
Agent 2: Gender: 男性
Trip ID: 1, Act ID: 10, Trip ID: 101, Day: 1
Trip ID: 2, Act ID: 20, Trip ID: 201, Day: 2
Agent 3: Gender: その他(未回答)
Trip ID: 1, Act ID: 10, Trip ID: 102, Day: 1
Trip ID: 2, Act ID: 20, Trip ID: 202, Day: 2
Agent 4: Gender: 女性
Trip ID: 1, Act ID: 10, Trip ID: 103, Day: 1
Trip ID: 2, Act ID: 20, Trip ID: 203, Day: 2
Agent 5: Gender: 男性
Trip ID: 1, Act ID: 10, Trip ID: 104, Day: 1
Trip ID: 2, Act ID: 20, Trip ID: 204, Day: 2
このプログラムの後ろに、Agent 4を変更するプログラムを追加したい、とする。
Agent 4は
(1)hh_idを1000, idv_idを1001, sexを2、no_answerを1
(2)
Trip ID: 123, Act ID: 456, Trip ID: 789, Day: 1
Trip ID: 321, Act ID: 654, Trip ID: 987, Day: 2
とするプログラムは以下のようになる。
package main
import (
"errors"
"fmt"
)
// Trip構造体の定義
type Trip struct {
id int
act_id int
trip_id int
day int
}
// Agent構造体の定義
type Agent struct {
hh_id int
idv_id int
trip []Trip
sex int
no_answer int
}
// getGenderメソッドの定義
func (a Agent) getGender() (string, error) {
switch a.sex {
case 1:
return "女性", nil
case 2:
return "男性", nil
case 3:
return "その他(未回答)", nil
default:
return "", errors.New("invalid sex value")
}
}
func main() {
// エージェントを5個生成
agents := make([]Agent, 5)
for i := 0; i < 5; i++ {
agents[i] = Agent{
hh_id: i + 1,
idv_id: i + 1,
sex: (i % 3) + 1, // 1, 2, 3をループ
trip: []Trip{
{id: 1, act_id: 10, trip_id: 100 + i, day: 1},
{id: 2, act_id: 20, trip_id: 200 + i, day: 2},
},
}
}
// 各エージェントの性別とTrip情報を表示
for i, agent := range agents {
gender, err := agent.getGender()
if err != nil {
fmt.Printf("Agent %d: Error: %v\n", i+1, err)
} else {
fmt.Printf("Agent %d: Gender: %s\n", i+1, gender)
}
for _, trip := range agent.trip {
fmt.Printf("\tTrip ID: %d, Act ID: %d, Trip ID: %d, Day: %d\n", trip.id, trip.act_id, trip.trip_id, trip.day)
}
}
// Agent 4を変更
agentIndex := 3
if agentIndex < len(agents) {
agents[agentIndex] = Agent{ // for i, agent := range agents のagentに上書きしても反映されない
hh_id: 1000,
idv_id: 1001,
sex: 2,
no_answer: 1,
trip: []Trip{
{id: 123, act_id: 456, trip_id: 789, day: 1},
{id: 321, act_id: 654, trip_id: 987, day: 2},
},
}
}
// 変更後のエージェント情報を表示
fmt.Println("\nAfter modification:")
for i, agent := range agents {
gender, err := agent.getGender()
if err != nil {
fmt.Printf("Agent %d: Error: %v\n", i+1, err)
} else {
fmt.Printf("Agent %d: Gender: %s\n", i+1, gender)
}
fmt.Printf("Agent %d: hh_id:%d, idv_id:%d, no_answer:%d\n", i+1, agent.hh_id, agent.idv_id, agent.no_answer)
for _, trip := range agent.trip {
fmt.Printf("\tTrip ID: %d, Act ID: %d, Trip ID: %d, Day: %d\n", trip.id, trip.act_id, trip.trip_id, trip.day)
}
}
}
出力結果
tomoi@DESKTOP-1QS7OI7 MSYS /g/home/ebata/tomioka3B/src/others
$ go run main85.go
Agent 1: Gender: 女性
Trip ID: 1, Act ID: 10, Trip ID: 100, Day: 1
Trip ID: 2, Act ID: 20, Trip ID: 200, Day: 2
Agent 2: Gender: 男性
Trip ID: 1, Act ID: 10, Trip ID: 101, Day: 1
Trip ID: 2, Act ID: 20, Trip ID: 201, Day: 2
Agent 3: Gender: その他(未回答)
Trip ID: 1, Act ID: 10, Trip ID: 102, Day: 1
Trip ID: 2, Act ID: 20, Trip ID: 202, Day: 2
Agent 4: Gender: 女性
Trip ID: 1, Act ID: 10, Trip ID: 103, Day: 1
Trip ID: 2, Act ID: 20, Trip ID: 203, Day: 2
Agent 5: Gender: 男性
Trip ID: 1, Act ID: 10, Trip ID: 104, Day: 1
Trip ID: 2, Act ID: 20, Trip ID: 204, Day: 2
After modification:
Agent 1: Gender: 女性
Agent 1: hh_id:1, idv_id:1, no_answer:0
Trip ID: 1, Act ID: 10, Trip ID: 100, Day: 1
Trip ID: 2, Act ID: 20, Trip ID: 200, Day: 2
Agent 2: Gender: 男性
Agent 2: hh_id:2, idv_id:2, no_answer:0
Trip ID: 1, Act ID: 10, Trip ID: 101, Day: 1
Trip ID: 2, Act ID: 20, Trip ID: 201, Day: 2
Agent 3: Gender: その他(未回答)
Agent 3: hh_id:3, idv_id:3, no_answer:0
Trip ID: 1, Act ID: 10, Trip ID: 102, Day: 1
Trip ID: 2, Act ID: 20, Trip ID: 202, Day: 2
Agent 4: Gender: 男性
Agent 4: hh_id:1000, idv_id:1001, no_answer:1
Trip ID: 123, Act ID: 456, Trip ID: 789, Day: 1
Trip ID: 321, Act ID: 654, Trip ID: 987, Day: 2
Agent 5: Gender: 男性
Agent 5: hh_id:5, idv_id:5, no_answer:0
Trip ID: 1, Act ID: 10, Trip ID: 104, Day: 1
Trip ID: 2, Act ID: 20, Trip ID: 204, Day: 2