世界を動かす技術を、日本語で。

新しい実験的なGoのJSON用API

2025年9月9日原文(go.dev)

概要

  • Go 1.25で新たに導入された encoding/json/v2encoding/json/jsontext パッケージの紹介
  • 既存の encoding/json パッケージの課題とその解決策の提案
  • jsontext パッケージの役割とAPI概要
  • v2パッケージの開発背景とコミュニティ主導の経緯
  • 新APIの利用方法と今後の展望

GoのJSON対応の進化:encoding/json/v2とjsontextの登場

  • JSON はインターネット上で最も広く使われるデータフォーマットであり、Go言語でも多く利用される現状
  • 既存の encoding/json (v1)は柔軟性が高い一方、標準化やセキュリティ、パフォーマンス面で多くの課題
    • 無効なUTF-8の許容や、重複メンバー名の処理不備
    • nilスライス・マップの扱い、ケース非依存のフィールド解決
    • メソッド呼び出しの不整合、APIの使い勝手の悪さ
    • ストリーミング処理の非効率性やメモリ消費
  • 既存APIの後方互換性維持のため、直接の修正が困難
    • 新バージョンとして encoding/json/v2 の開発を決断
  • v2の計画は5年以上にわたり、Goコミュニティ主導で進行
    • Daniel MartíやJoe Tsaiらによる設計・実装
    • GopherConでの発表や公開ミーティング、提案文書を経てGo 1.25で実験的導入

jsontextパッケージの基礎とAPI概要

  • jsontext はJSONの構文レベルの処理専用パッケージ
    • 構文(エンコード/デコード)と意味(マシャル/アンマシャル)を明確に分離
  • 主な型と関数
    • Encoder/Decoder :io.Writer/io.Readerベースでストリーミング処理
      • NewEncoder(io.Writer, ...Options) *Encoder
      • NewDecoder(io.Reader, ...Options) *Decoder
    • Value 型:JSON値の[]byte表現(v1のRawMessageと同等)
    • Token 型:JSONトークンの効率的な表現(アロケーション削減設計)
  • オプション による動作カスタマイズが可能
  • v1とは異なり、構文と意味付けを混同せず、純粋なストリーミング処理を実現

v2 APIの特徴と改善点

  • MarshalJSONTo/UnmarshalJSONFrom インターフェースでストリーミング指向の拡張
    • これによりバリデーションやフォーマット調整の責任をEncoder/Decoderに分離
  • v1の既存問題(パフォーマンス、セキュリティ、カスタマイズ性)を根本から解決
  • v1からv2への移行も容易に設計、既存ユーザーへの配慮

今後の展望とコミュニティへの呼びかけ

  • encoding/json/v2jsontext は実験的な段階であり、API変更の可能性あり
  • 広範なユーザーテストとフィードバックを通じて安定版へ発展予定
  • Google以外の開発者主導で進化するGoエコシステムの象徴例

Go 1.25以降、 encoding/json/v2jsontext の活用により、より安全で高速・柔軟なJSON処理が可能となる。今後もコミュニティの参加とフィードバックが、GoのJSONエコシステムの進化を後押しする。

Hackerたちの意見

ベンチマーク分析:Sonic vs Standard JSON vs JSON v2 in Go https://github.com/centralci/go-benchmarks/tree/b647c45272c7...

確か、sonicはJITやインラインアセンブリ(GitHubによると41%)を使ってて、かなり大きいんだよね。監査するのは無理だと思う。もしJSONパーサーから毎秒のCPUサイクルを絞り出す必要がなければ(ほとんどの人はそうだし、そもそもGoはそんなパフォーマンスを求める選択肢じゃない)、もっとシンプルな実装にした方がいいと思うよ。

その数字、goccyに似てるね。昔使ってたけど、Kubernetesでも直接依存してるし、でも問題がかなり積み重なってきたから、もう信頼できない。どうやら両方ともGoの限界で動いてるみたい。個人的には、JSONはGoのコアにあって、SIMD最適化されたCコードで実装されるべきだと思う。今のウェブではJSONがすごく重要な部分だから、もっと丁寧に扱われるべきだよね。

まず第一に、それはJSON v2を全く使ってないと思う。第二に、Sonicはバイトスライスを文字列に(unsafeに)キャストするのにunsafeを使ってるみたいで、もちろんそれは正しくやるよりも速いけど、正しくやることと比べると全然比較にならないよね。ほとんどのベンチマークデータがHNに投稿されてるけど、あれは信頼できないから無視して。

Sonicの「最先端」最適化でも、基本的な使い方ではarm64のstd Jsonより遅いんだよね。JITやSIMD、低レベルのコードは全プラットフォームのメンテナンスコストがかかることを示してる。

null != nil !!! この問題に対する部分的な解決策が見られて嬉しい。ほとんどの言語でこの問題に悩まされてて、ちょっとした曖昧さを生んでるから、いつかトラブルになるよね。皮肉なことに、JavaScriptは面白いnullundefinedがあって、この問題はないんだよね。ほとんどの言語のJSONパーサーやエミッターは、「JSON null」のために特別な値を使うべきだと思う。

1976年にMLで修正され、2005年にEiffelでもフォローされたけど、残念ながらまだ一般的にはなってないね。

nullとundefinedは、空っぽや欠けてる意味合いでいいと思うよ(特に、==で比較することが多いから)。undefinedなキーと未定義なキーが似てるのに違うってのが、もっと大きな問題だな。obj['key']=undefinedがdelete obj['key']と同じだったら、むしろそっちの方がいいかも。

時間が経つにつれて、パッケージはユーザーのニーズに応じて進化し、encoding/jsonも例外ではありません。 いや、これは例外だよ。最初からデザインが悪かったんだ。人々のJSONのニーズ(ほとんど変わってない)を超えてしまったわけじゃないんだよ。

悪いデザインだからって、君が引用した文が無効になるわけじゃないよ。時間が経つにつれて、JSONパッケージがユーザーのニーズを満たしていないことが明らかになって、その結果としてパッケージは進化したんだ。進化の大きさは関係ない。

まあ、ほとんどの人はソフトウェアを使ったり作ったりすることで欠点を学んで、新しいバージョンを作ることが多いよね。君の場合、v1は毎回完璧みたいだね。

誰か、これを高レベルでざっくり説明してくれない?私はgodevじゃないから。GoのJSONライブラリがネイティブのGo構造体をJSONにエンコードするサポートがあるみたいで、クールだけど、もしかしたらそれが悪かったのかな?それで合ってる?

Hacker Newsで議論の続きを見る