Help us understand the problem. What is going on with this article?

goのforループ変数の補足問題

More than 1 year has passed since last update.

goのforループ変数は同じ変数を共有します。
ループ内の変数の処理を後から利用しようとするとループの最後の値になってしまいます。
deferとかの時にバグをうみやすいので注意が必要です。

// loop_scope.go
package main

import (
    "fmt"
)

func main() {
    strings := []string{"a", "b", "c"}
    var printFuncList []func()

    // ループ変数sは各ループ処理で使い回されるので、無名関数からは同じ変数の値が表示されてしまいます
    for _, s := range strings {
        printFuncList = append(printFuncList, func() {
            fmt.Printf("s = \"%s\" (%p)\n", s, &s)
        })
    }

    // 何らかの処理

    for _, printFunc := range printFuncList {
        printFunc()
    }
}

// 実行結果 最後の変数の値が表示されてしまう
go run loop_scope.go
s = c (0xc00000e1e0)
s = c (0xc00000e1e0)
s = c (0xc00000e1e0)

そのため、変数宣言をする必要があります。

// loop_scope.go
package main

import (
    "fmt"
)

func main() {
    strings := []string{"a", "b", "c"}
    var printFuncList []func()

    for _, s := range strings {
        s := s // この変数宣言が必要
        printFuncList = append(printFuncList, func() {
            fmt.Printf("s = \"%s\" (%p)\n", s, &s)
        })
    }

    // 何らかの処理

    for _, printFunc := range printFuncList {
        printFunc()
    }
}

// 実行結果 適切にそれぞれの値が表示される
go run loop_scope.go
s = a (0xc00000e1e0)
s = b (0xc00000e200)
s = c (0xc00000e230)
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away