1 ポイント 投稿者 GN⁺ 2 시간 전 | 1件のコメント | WhatsAppで共有
  • 今回のリリースでは ジェネリックメソッド を中心に構造体リテラルと型推論が改善され、標準ライブラリ・ランタイム・ツールチェーン全体に実用的な機能が追加された
  • サイズ特化メモリアロケーション により、80バイト未満の一部の割り当てコストを最大30%削減し、割り当て集約型プログラムでは約1%の性能向上と約60KBのバイナリ増加が見込まれる
  • encoding/json/v2 が正式提供され、既存の encoding/json も内部的に v2 を使用し、標準の UUID パッケージ と FIPS 204 ベースの ML-DSA 署名が追加された
  • goroutineleak プロファイル、traceback の pprof ラベル、仮想時間用 synctest.Sleep、インメモリ HTTP テストサーバーにより、診断と並行性テスト が容易になった
  • タイマーチャネルの非バッファ化、HTTP レスポンスボディの自動消費、//go:linkname 制限の強化は既存コードに影響する可能性があり、Go 1.27 への移行前に互換性チェック が必要

言語と型システム

  • Go 1.27 の中核である ジェネリックメソッド は、レシーバとは独立した独自の型パラメータを宣言できる
    • 以前はトップレベル関数だけがジェネリックにできたため、型に属する演算もパッケージ関数として書く必要があった
    • Box[T].Map[U] のように、入力とは異なる要素型を返す演算をメソッドとして定義できる
    • インターフェースは依然として型パラメータ付きメソッドを宣言できず、ジェネリックメソッドでインターフェースを実装することもできない
  • 構造体リテラルのキー には、トップレベルのフィールド名だけでなく有効なフィールドセレクタも使える
    • 埋め込み構造体で昇格したフィールドを User{ID: 7} のように直接初期化できる
  • 関数の型推論 が変換と複合リテラルにまで拡張された
    • []func([]int) int{first, last} のように、期待される関数型に基づいてジェネリック関数の型引数を推論する
    • 以前は first[int]last[int] のように直接インスタンス化する必要があった

ランタイムと性能

  • コンパイラが サイズ特化割り当てルーチン を呼び出し、80バイト未満の一部メモリ割り当てコストを最大30%削減する
    • 実際の割り当て集約型プログラムでの全体的な性能向上は約1%と見込まれる
    • コード修正は不要だが、ワークロードに関係なくバイナリは約60KB大きくなる
    • GOEXPERIMENT=nosizespecializedmalloc で無効化できるが、このオプションは Go 1.28 で削除予定
  • デフォルトで有効化されるコンパイラ最適化が3つ追加された
    • 値の中で確実に 0 または 1 であるビットを追跡して冗長な演算を除去する known bits データフローパス
    • 反復中に変化しない計算をループ外へ移動するループ不変コード移動
    • 条件が合えば switchfallthrough まで含めてルックアップテーブルにコンパイルする
  • 実験的な GOEXPERIMENT=mapsplitgroup は、マップグループのメモリレイアウトを KVKVKVKV から KKKKVVVV に変更し、デフォルトでは無効
  • リンカは型ディスクリプタと itab を専用の .go.type セクションへ移し、typelinksitablinks を削除する
    • reflect.typelinks がオフセットではなく型を返すようになるため、このシンボルに //go:linkname でアクセスするライブラリは影響を受ける可能性がある

ゴルーチン診断とプロファイリング

  • go.mod が Go 1.27 以上のモジュールでは、traceback のゴルーチンヘッダーに runtime/pprof ラベルが表示される
    • pprof.Do で付与した {request: 42} のようなコンテキストが、クラッシュダンプ、SIGQUITruntime.Stack の出力に現れる
    • 機密性の高いラベルが traceback に露出しないよう、GODEBUG=tracebacklabels=0 を引き続き使用できる
  • Go 1.26 の実験機能だった ゴルーチンリーク検出器 が正式な goroutineleak プロファイルへ昇格した
    • GC を実行して、チャネルやミューテックスなどで永遠に進行できないゴルーチンを見つけ、スタックを出力する
    • サービスでは /debug/pprof/goroutineleak エンドポイントから収集でき、GOEXPERIMENT は不要

暗号と識別子

  • 新しい crypto/mldsa パッケージは、FIPS 204 の 耐量子署名 ML-DSA を実装する
    • MLDSA44MLDSA65MLDSA87 の3つのパラメータセットが、鍵・署名サイズとセキュリティレベルのトレードオフを提供する
    • crypto/x509 の鍵・署名と crypto/tls の TLS 1.3 署名方式にも ML-DSA が追加された
  • 標準ライブラリの新しい uuid パッケージは、RFC 9562 UUID を暗号学的に安全な乱数で生成・解析する
    • uuid.New() は一般用途に適した方式を選び、NewV4() は純粋な乱数、NewV7() は生成時刻順の UUID を作る
    • 乱数ベースの UUID は比較可能で、== を直接使用できる
    • 時系列順にソートされる UUID v7 はデータベースキーに適している

JSON とデータ処理 API

  • encoding/json/v2 と低レベルの encoding/json/jsontextGOEXPERIMENT=jsonv2 なしで提供される
    • 既存の encoding/json v1 も内部的に v2 実装 を使用する
    • 一部のエラーメッセージ文言を除き既存の動作を維持するため、移行は不要
    • 互換性の問題があれば GOEXPERIMENT=nojsonv2 で元の v1 実装に戻せる
    • v2 は性能のためマップキーをデフォルトでソートしないため、安定した出力が必要なテストでは json.Deterministic を指定する必要がある
  • strings.CutLastbytes.CutLast は、最後の区切り文字を基準に値を分割する
    • 区切り文字がなければ、入力全体、空の後半部、false を返す
  • hash/maphash のジェネリック Hasher[T] は、値の ハッシュと等価性の戦略 をまとめて定義する
    • 等価な値は必ず同じハッシュを持たなければならない
    • 比較可能型向けの ComparableHasher[T] が提供され、大文字小文字を無視する文字列のようなユーザー定義戦略も実装できる
  • math/big.Int.Divide は、商と余りを同時に計算しながら TruncFloorRoundCeil のいずれかの明示的な丸め方式を適用する
    • 丸め方式によって余りも変わるため、金融・数値コードにおいて既存の QuoMod の 0 方向切り捨ての限界を補う
  • math/rand/v2.(*Rand).N は、自身の *Rand ソースから任意の整数または duration 型に対する範囲制限付き乱数を生成する

ポータブル SIMD

  • 実験的な simd パッケージは、ベクトルサイズ非依存の SIMD API を提供し、GOEXPERIMENT=simd で有効化する
    • 対応環境では実際のハードウェアベクトル命令にコンパイルされ、そうでなければ純粋な Go エミュレーションに置き換えられる
    • Float32s のような型のレーン数は固定ではなく、マシンごとのハードウェア幅に従う
  • 標準ライブラリはすでに内部の simd/archsimd intrinsics を使用している
    • Swiss Table マップの MemHash32MemHash64StrHash が新しい SIMD ベースで再実装された

決定論的テスト

  • testing/synctest.Sleep は、仮想時間を進め、すべてのゴルーチンが安定するまで待つ処理を一度に行う
    • synctest バブル内では実時間が流れないため、2秒待機も即座に完了する
    • 既存の time.Sleepsynctest.Wait の組み合わせによる繰り返しコードを置き換える
  • httptest.NewTestServer は、実際の TCP ポートではなく インメモリ仮想ネットワーク でサーバーを実行する
    • srv.Client() がプロセス内部のパイプでハンドラに直接接続される
    • t.Cleanup により自動でクリーンアップされるため、defer srv.Close() は不要
    • testing/synctest と組み合わせると、HTTP ラウンドトリップも仮想時間上で高速かつ決定論的にテストできる

ネットワークと互換性の変更

  • time.Aftertime.NewTimertime.NewTicker などが返すチャネルは、常に 同期式の非バッファチャネル になる
    • 以前のバッファ動作を復元していた asynctimerchan GODEBUG 設定は削除された
  • HTTP/1 では http.Response.Body.Close が未読のボディを保守的な上限まで読み取り、接続再利用を助ける
    • 大きなダウンロードを早期終了するために Close に依存していたなら、Transport.DisableKeepAlives で再利用を無効化する必要がある
  • HTTP/2 サーバーは RFC 9218 のクライアント優先度を理解し、高優先度のストリームから処理する
    • Server.DisableClientPriority = true で従来のラウンドロビン動作を復元できる
  • Windows と macOS の crypto/x509.SystemCertPoolSSL_CERT_FILESSL_CERT_DIR をサポートする
    • 変数が設定されている場合、ディスク上のルート証明書を読み込み、プラットフォーム API の代わりに Go の検証器を使う
    • GODEBUG=x509sslcertoverrideplatform=0 で無効化できる
  • これまで 12,226 行の生成ファイル h2_bundle.go に含まれていた HTTP/2 実装が、実際の net/http/internal/http2 パッケージに置き換えられた
  • net/http には、外部公開前段階のプラグ可能な HTTP/3 フック が追加され、テストスイートの一部が HTTP/3 で実行される
    • 呼び出し可能な公開 API はまだないが、将来の QUIC ベース http.Transport のための基盤が含まれている

ツールチェーン

  • go test は、go.mod に宣言された Go バージョンより新しい標準ライブラリシンボルの使用を見つける stdversion vet チェック をデフォルトで実行する
  • go doc pkg@version で特定モジュールバージョンのドキュメントを参照できる
  • go doc -ex は実行可能なサンプルを一覧表示し、サンプル名を直接指定するとソースを出力する
  • go fixatomictypesembedlitslicesbackwardunsafefuncs のモダナイズ用アナライザーが追加された
    • waitgroupwaitgroupgo に名前変更され、fmtappendf は削除された
  • Go 1.27 以上のモジュールで go mod tidy は、散在した require ブロックを直接・間接依存関係用の2ブロックに統合しつつコメントを保持する
  • go tool trace -http=:6060 はポートだけを指定した場合 localhost のみにバインドし、外部アクセスにはアドレス指定が必要
  • go コマンドは Bazaar(bzr) バージョン管理システムのサポートを削除した
  • compilelinkasmcgocoverpack は、GCC 形式の レスポンスファイル(@file) をサポートし、コマンドライン長の制限を回避できる

Unicode とセキュリティ境界

  • 標準ライブラリの Unicode データが Unicode 15 から Unicode 17 に更新された
    • Unicode 16 で追加された文字も、記号・表示可能文字として正しく分類される
  • os.Root.ReadDirReaddir を使ってルート外へ脱出できていた問題が修正された
  • 未承認の //go:linkname 使用はさらに難しくなった
    • linknamestd ディレクティブは、標準ライブラリだけが取り込める linkname を示す
    • リンカがアセンブリシンボルへの linkname アクセスも検査するため、非公式の内部シンボルに依存するコードは早めのテストが必要

1件のコメント

 
GN⁺ 2 시간 전
Lobste.rs のコメント
  • 史上最高のリリースかもしれない。SIMD、uuid、jsonv2 がついに入った

    • UUID v5 もサポートされれば、完全に移行できそう
  • やや話題から外れるが、すべてを文字列として扱い、インターフェースメソッド間の契約や関連性を考慮しないとバグが生まれる好例
    Equal は大文字小文字を無視するが、Hash は小文字に変換した値を使う。しかし EqualFoldToLower は同じ同値関係を定義していない
    https://github.com/golang/go/issues/52204
    "\u017F"(ſ、長い s)と "s"EqualFold では等しいが、それぞれを ToLower した結果は異なる。そのため "s" を入れた後に "ſ" を入れると、ハッシュが異なるため別項目として挿入される
    さらに面白いのは、ドキュメントがまさにこのケースを警告している点
    https://github.com/golang/go/…

    • 公平に見ると、ドキュメントには 単純 Unicode case folding の基準で等しいと明確に書かれている
      https://github.com/golang/go/…
  • Anton が止まったところから別の人が引き継いでくれてうれしい

    • 残念ながら、少なくとも一部、特に JSON v2 のデフォルト使用 の部分は LLM で書かれたように見える。文体は好みではないが、内容は依然として興味深い
    • Anton が中断したわけではなさそう。1.26 も書いているので、今回は別の人が先に公開したように見える
  • Go は好きだが、リリースごとにこうした機能を追加し続けるには、Go の構文 が十分にエレガントなのか疑問
    func (b Box[T]) Map[U any](f func(T) U) Box[U] {

    • 主観的だが、この機能をサポートする他の言語より悪いとは思わない。Zig が最も近く、Rust・TypeScript・C++20 はおおむね型をメソッド定義のコンテナとして扱い、複数のメソッドでレシーバ型を繰り返すコストを減らしている
      一方で Go と Zig の冗長さは、レシーバの定義を探すために別の場所へスクロールする必要がない点でよい。定義部より重要ともいえる 呼び出し箇所 では、どれもほとんど同じに見え、型を明示する必要もない
  • しばらく Go から離れていたが、jsonv2 には期待している。ただ、デフォルトになるなら、Go が長年守ってきた互換性の約束を破ることにならないのか気になる

    • jsonv2 は別パスの encoding/json/v2 からインポートする必要があるため、自分で選択する形になる。既存の encoding/json は内部的に v2 を使うが従来の動作を保証し、jsonv2 には v1 の例外的な動作を再現するフラグも用意されているので、互換性の約束 は破らない
    • Go 1.26 プロジェクトで v2 の jsontext ライブラリ を使っているが、とても満足している