概要
以下のプログラムの出力結果はどうなるでしょうか?
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) } }
A
B
C
の順番で出力されることを期待するかもしれませんが、実際は以下のようになります。
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