Go 1.23リリース - イテレーターとテレメトリー

2025.12.12

Go 1.23の概要

2024年8月にリリースされたGo 1.23は、長らく待望されていたイテレーター機能(range over func)を導入し、標準ライブラリにも多くの改善が加えられました。

参考: Go 1.23 Release Notes

range over func(イテレーター)

基本的な使い方

関数をforループで直接イテレートできるようになりました。

package main

import "fmt"

// イテレーター関数を定義
func Backward[E any](s []E) func(yield func(E) bool) {
    return func(yield func(E) bool) {
        for i := len(s) - 1; i >= 0; i-- {
            if !yield(s[i]) {
                return
            }
        }
    }
}

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

    // イテレーターを使用
    for v := range Backward(s) {
        fmt.Println(v) // c, b, a
    }
}

iter パッケージ

新しい標準パッケージiterが追加されました。

import "iter"

// Seq: 値のシーケンス
type Seq[V any] func(yield func(V) bool)

// Seq2: キー・値ペアのシーケンス
type Seq2[K, V any] func(yield func(K, V) bool)

// Pull: pushスタイルをpullスタイルに変換
func Pull[V any](seq Seq[V]) (next func() (V, bool), stop func())

slicesパッケージの拡張

import "slices"

s := []int{1, 2, 3, 4, 5}

// All: 全要素をイテレート
for i, v := range slices.All(s) {
    fmt.Printf("index: %d, value: %d\n", i, v)
}

// Backward: 逆順でイテレート
for i, v := range slices.Backward(s) {
    fmt.Println(i, v)
}

// Values: インデックスなしで値のみ
for v := range slices.Values(s) {
    fmt.Println(v)
}

// Chunk: n個ずつに分割
for chunk := range slices.Chunk(s, 2) {
    fmt.Println(chunk) // [1 2], [3 4], [5]
}

参考: Go iter package

mapsパッケージの拡張

import "maps"

m := map[string]int{"a": 1, "b": 2, "c": 3}

// Keys: キーのイテレーター
for k := range maps.Keys(m) {
    fmt.Println(k)
}

// Values: 値のイテレーター
for v := range maps.Values(m) {
    fmt.Println(v)
}

// All: キーと値のイテレーター
for k, v := range maps.All(m) {
    fmt.Printf("%s: %d\n", k, v)
}

// Insert: イテレーターからマップに挿入
maps.Insert(m, slices.All([]struct{k string; v int}{{"d", 4}}))

uniqueパッケージ

メモリ効率の良い値の正規化(インターニング)を提供します。

import "unique"

// 文字列の正規化
h1 := unique.Make("hello")
h2 := unique.Make("hello")

// 同じ文字列は同じハンドルを返す
fmt.Println(h1 == h2) // true

// 値の取得
fmt.Println(h1.Value()) // "hello"

// 比較可能な任意の型で使用可能
type Point struct{ X, Y int }
p1 := unique.Make(Point{1, 2})
p2 := unique.Make(Point{1, 2})
fmt.Println(p1 == p2) // true

参考: Go unique package

time.Timerの改善

ガベージコレクションとチャネル動作が改善されました。

import "time"

// 未使用のTimerはGCで自動回収される
timer := time.NewTimer(time.Hour)
// timer.Stop()を呼ばなくてもGCされる

// Resetの動作が改善
timer = time.NewTimer(time.Second)
if !timer.Stop() {
    // Go 1.23: チャネルは自動的にドレインされる
    // 以前: <-timer.C が必要だった
}
timer.Reset(time.Minute)

structs パッケージ(実験的)

構造体のレイアウトを制御できます。

import "structs"

type Data struct {
    _     structs.HostLayout  // ホストのレイアウトを使用
    Value int64
}

テレメトリー

Go ツールチェーンの使用状況を収集する機能が追加されました。

# テレメトリーの状態確認
go telemetry

# テレメトリーを有効化(オプトイン)
go telemetry on

# テレメトリーを無効化
go telemetry off

# ローカルのみ(アップロードなし)
go telemetry local

参考: Go Telemetry

ツールチェーンの改善

go vetの強化

// 新しい警告: ループ変数のキャプチャ(Go 1.22から引き続き)
for _, v := range values {
    go func() {
        fmt.Println(v) // 警告なし(Go 1.22+で修正済み)
    }()
}

go mod の改善

# 依存関係のツリー表示が改善
go mod graph

# より詳細なバージョン情報
go version -m ./binary

パフォーマンス改善

項目Go 1.22Go 1.23
コンパイル速度基準+3%
PGO効果2-7%2-9%
GCレイテンシ基準-5%

PGO(Profile-Guided Optimization)

# プロファイル収集
go test -cpuprofile=default.pgo -bench=.

# PGOを使用してビルド
go build -pgo=auto

まとめ

Go 1.23は、言語機能とツールチェーンの両面で重要な進化を遂げました。

  • range over func: 待望のイテレーター機能
  • iterパッケージ: 標準ライブラリでのイテレーターサポート
  • uniqueパッケージ: メモリ効率の良い値の正規化
  • time.Timer改善: GCとAPIの改善
  • テレメトリー: ツールチェーン改善のためのデータ収集

特にイテレーター機能は、Goのコードスタイルに大きな影響を与えるでしょう。

← 一覧に戻る