こぼれネット

具体的には、以下のようなコードでは、agent変数はスライスagentsの要素をコピーしたものであり、変更はagentsスライス自体には反映されません。

これから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

モバイルバージョンを終了