概要
以下のプログラムの出力結果はどうなるでしょうか?
package main
import "fmt"
func main() {
a := []string{"A", "B", "C"}
var b []*string
for _, str := range a {
b = append(b, &str)
}
for _, str := range b {
fmt.Println(*str)
}
}
出力結果は以下のようになります。
C
C
C
解説と検証コード
strがループ中にずっと同じポインタになっていることが原因です。
以下のプログラムで&str
の値を出力してみます。
つまり、str
が指している領域のアドレスを出力します。
package main
import "fmt"
func main() {
a := []string{"A", "B", "C"}
for _, str := range a {
fmt.Println(&str)
}
}
以下のように、ループ中に常に同じアドレスになっています。
0xc42000e1e0
0xc42000e1e0
0xc42000e1e0
つまり _, str := range a
を実行するたびに、同じ領域の値を上書きしていっているということです。
最初のコード例では、bの配列に上記の結果が入るため、ループの最後で上書きされるC
が出力されます。
意図した処理にするには?
インデックス変数を使うようにすると良さそうです。
package main
import "fmt"
func main() {
a := []string{"A", "B", "C"}
var b []*string
n := len(a)
for i := 0; i < n; i++ {
b = append(b, &a[i])
}
for _, str := range b {
fmt.Println(*str)
}
}
A
B
C
参考
Goのfor rangeでポインタを使用する際に気をつけたいこと
https://qiita.com/RunEagler/items/008e2b304f27b7fb168a