📣

【Go 1.22】for ループの2つの仕様変更

2024/02/07に公開

Go 1.22 がリリースされましたね。

本記事では、個人的に今リリースで最もインパクトの大きい仕様変更である、for ループに関する2つの変更について簡単にまとめます。

https://tip.golang.org/doc/go1.22

変数がイテレート毎に宣言されるようになった

1.21 以前では、for ループの range 句で宣言された変数は各イテレートで値が更新されながら使いまわされていました。
そのため、宣言された変数を goroutine で使用したり defer による遅延処理で使用するケースなどで面倒な処理が必要でした。
具体的には、別途宣言した変数に代入するか、即時関数の引数として渡す必要がありました。

package main

import (
    "fmt"
    "time"
)

func main() {
    for _, v := range []int{1, 2, 3} {
        go func(n int){
            fmt.Println(n)
        }(v)
    }
    // ちょっと待つ
    time.Sleep(1 * time.Second)
}
package main

import (
    "fmt"
    "time"
)

func main() {
    for _, v := range []int{1, 2, 3} {
        n := v
        go func(){
            fmt.Println(n)
        }()
    }
    // ちょっと待つ
    time.Sleep(1 * time.Second)
}

1.22 からは、イテレート毎に新しい変数が宣言されるようになりました。
1.21 以前で行っていたような処理は不要となり、変数をそのまま goroutine や defer で使用するだけで各イテレートで宣言された変数を用いた動作が得られます。

package main

import (
    "fmt"
    "time"
)

func main() {
    for _, v := range []int{1, 2, 3} {
        go func(){
            fmt.Println(v)
        }()
    }
    // ちょっと待つ
    time.Sleep(1 * time.Second)
}

range 句の式に整数を渡せるようになった

1.21 以前では、0から2までの範囲で処理したいといったように、0から任意の正の数まで1ずつ増加する値をループで処理したい場合は、[]int{0, 1, 2}を渡したり、要素数が3つの何らかのスライスを渡す必要がありました。

package main

import (
    "fmt"
)

func main() {
    for _, v := range []int{0, 1, 2} {
        fmt.Println(v)
    }
}

1.22 からは range 句の式に整数を渡すことで、0から渡した整数 -1までの範囲を反復して処理できるようになりました。

package main

import (
    "fmt"
)

func main() {
    for v := range 3 {
        fmt.Println(v)
    }
}

Discussion