Goのfor rangeでポインタを使用する際に気をつけたいこと

## 該当ケース

ある構造体配列をポインタの参照渡しで別の構造体配列にコンバートする際にfor rangeを使用する

## 実装例
### Employee型配列をPEmployee型配列に値をコピーする
```sample.go
package main

import "fmt"

type Employee struct{
	ID int
	Name string
	Age int
	Sex string
}

type PEmployee struct{
	ID *int
	Name *string
	Age *int
	Sex *string
}

func convertPEmployee(employees []Employee) []PEmployee{

	var pEmployees []PEmployee
	for _,employee := range employees{
		pEmployees = append(pEmployees,PEmployee{
			ID: &employee.ID,
			Name: &employee.Name,
			Age: &employee.Age,
			Sex: &employee.Sex,
		})
	}
	return pEmployees
}

func main(){

	employees := []Employee{
		Employee{
			ID:   1,
			Name: "山田太郎",
			Age:  23,
			Sex:  "男",
		},
		Employee{
			ID:   2,
			Name: "山田花子",
			Age:  27,
			Sex:  "女",
		},
		Employee{
			ID:   3,
			Name: "田中次郎",
			Age:  36,
			Sex:  "男",
		},
	}
	pEmployees := convertPEmployee(employees)

	fmt.Println("==PEmployees==")
	for _,pEmployee := range pEmployees{
		fmt.Println("ID = ",*pEmployee.ID)
		fmt.Println("Name = ",*pEmployee.Name)
		fmt.Println("Age = ",*pEmployee.Age)
		fmt.Println("Sex = ",*pEmployee.Sex)
		fmt.Println("--")
	}
}
```
上記のsample.goを実行すると以下のようになる

```
ID =  3
Name =  田中次郎
Age =  36
Sex =  男
ID =  3
Name =  田中次郎
Age =  36
Sex =  男
ID =  3
Name =  田中次郎
Age =  36
Sex =  男
```
## 解説

結論をいうと**for rangeのrangeの返り値には同じ参照先が使用されている。**
上記のsample.goのconvertPEmployee関数を以下のように変更し、参照先を確認する。

```sample.go
func convertPEmployee(employees []Employee) []PEmployee{

	var pEmployees []PEmployee
	for _,employee := range employees{
		
		fmt.Println("==",i+1," loop==")
		fmt.Println("&i = ",&i)
		fmt.Println("&employee.ID = ",&employee.ID)
		fmt.Println("&employee.Name = ",&employee.Name)
		fmt.Println("&employee.Age = ",&employee.Age)
		fmt.Println("&employee.Sex = ",&employee.Sex)
		fmt.Println("&employee = ",employee)
		pEmployees = append(pEmployees,PEmployee{
			ID: &employee.ID,
			Name: &employee.Name,
			Age: &employee.Age,
			Sex: &employee.Sex,
		})
	}
	return pEmployees
}
```


###実行結果
```
== 1  loop==
&i =  0x8201cc288
&employee.ID =  0x8201d6180
&employee.Name =  0x8201d6188
&employee.Age =  0x8201d6198
&employee.Sex =  0x8201d61a0
&employee =  {1 山田太郎 23 男}
== 2  loop==
&i =  0x8201cc288
&employee.ID =  0x8201d6180
&employee.Name =  0x8201d6188
&employee.Age =  0x8201d6198
&employee.Sex =  0x8201d61a0
&employee =  {2 山田花子 27 女}
== 3  loop==
&i =  0x8201cc288
&employee.ID =  0x8201d6180
&employee.Name =  0x8201d6188
&employee.Age =  0x8201d6198
&employee.Sex =  0x8201d61a0
&employee =  {3 田中次郎 36 男}

```
i,employee共に同じアドレスが毎回使用されている
※値だけを出力させても一見変更されているように見えるので注意が必要。

## 解決策

別の作業用変数を新規に定義し、一時的に置き換える必要がある。
※employeeCopyにはループ毎に毎回新しいアドレスが割り当てられる

```sample.go
func convertPEmployee(employees []Employee) []PEmployee{

	var pEmployees []PEmployee
	for _,employee := range employees{
		employeeCopy := Employee{
			ID: employee.ID,
			Name: employee.Name,
			Age: employee.Age,
			Sex: employee.Sex,
		}
		pEmployees = append(pEmployees,PEmployee{
			ID: &employeeCopy.ID,
			Name: &employeeCopy.Name,
			Age: &employeeCopy.Age,
			Sex: &employeeCopy.Sex,
		})
	}
	return pEmployees
}

```
## 実行結果

```
==PEmployees==
ID =  1
Name =  山田太郎
Age =  23
Sex =  男
--
ID =  2
Name =  山田花子
Age =  27
Sex =  女
--
ID =  3
Name =  田中次郎
Age =  36
Sex =  男
--
```

## 最後に

簡単なことですが、ポインタの扱いに慣れていないと今回のようなことが起きるので参照先には
注意が必要ですね。
似たような実装でハマった方はぜひご参考にして頂ければ幸いです。