LoginSignup
39
21

More than 5 years have passed since last update.

Goのfor rangeでのポインタでハマったこと

Posted at

概要

以下のプログラムの出力結果はどうなるでしょうか?

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

39
21
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
39
21