メインコンテンツへスキップ

Go Proposal Weekly Digest

Go言語のproposal更新を毎週お届け

#62026accepted

uuid: add API to generate and parse UUID

ステータス変更: likely_accept accepted

要約

AIによる要約であり、誤りを含む場合があります。

概要

uuid パッケージを Go 標準ライブラリに追加し、UUID(Universally Unique Identifier)の生成とパースのための公式 API を提供するものです。RFC 9562 に準拠した実装で、暗号論的に安全な乱数生成器を使用します。

ステータス変更

likely_accept -> accepted
2026年4月8日、aclements がコンセンサスに変化がないことを確認し、正式に accepted と宣言しました。2025年11月に議論が本格化し、約5ヶ月間・338件を超えるコメントにわたる大規模な議論の末、提案レビューグループが最終的な API 設計を確定しました。

技術的背景

現状の問題点

Go の標準ライブラリには UUID を扱うパッケージが存在せず、エコシステムが分断されていました。github.com/google/uuid(11万2千件のインポート)を筆頭に、github.com/satori/go.uuid など複数の競合するサードパーティパッケージが乱立しており、UUID 型の相互互換性がないためパッケージ間でのデータの受け渡しに型変換が必要でした。2018年 (#23789) や 2019年 (#28324) にも同様の提案がありましたが、当時は採用されませんでした。今回はエコシステムの実態データ(使用状況分析)が揃い、標準 API の妥当性を実証できるようになったことが承認の大きな要因です。

提案された解決策

パッケージ名は uuid(当初案の crypto/uuid から変更)で、[16]byte を基底型とする UUID 型を中心に、以下のシンプルな API を提供します。

package uuid
type UUID [16]byte
// 生成
func New() UUID        // 現時点では NewV4 相当(将来変更可能)
func NewV4() UUID      // 122ビットの乱数から生成
func NewV7() UUID      // タイムスタンプ+乱数から生成(単調増加保証)
// パース
func Parse(s string) (UUID, error)
func MustParse(s string) UUID
// 特殊値
func Nil() UUID        // 00000000-0000-0000-0000-000000000000
func Max() UUID        // ffffffff-ffff-ffff-ffff-ffffffffffff
// シリアライズ
func (u UUID) String() string
func (u UUID) MarshalText() ([]byte, error)
func (u UUID) AppendText(b []byte) ([]byte, error)
func (u *UUID) UnmarshalText(b []byte) error
// 比較
func (u UUID) Compare(v UUID) int

また、database/sqlUUID 型を認識し、データベースドライバが独自処理しない場合は自動的に文字列(ハイフン区切り hex 形式)に変換するよう変更されます。

これによって何ができるようになるか

サーバーアプリケーションやデータベースを使用する Go プログラムでサードパーティ依存なしに UUID を扱えるようになります。

コード例

// Before: サードパーティパッケージへの依存が必要
import "github.com/google/uuid"
id := uuid.New()        // UUIDv4
idStr := id.String()    // "f81d4fae-7dec-11d0-a765-00a0c91e6bf6"
parsed, err := uuid.Parse("f81d4fae-7dec-11d0-a765-00a0c91e6bf6")
if err != nil {
    log.Fatal(err)
}
// After: 標準ライブラリのみで完結
import "uuid"
id := uuid.New()        // 現時点では UUIDv4 相当
id7 := uuid.NewV7()     // データベースのB-treeインデックスに適した単調増加UUID
parsed, err := uuid.Parse("f81d4fae-7dec-11d0-a765-00a0c91e6bf6")
// 以下の形式もすべて受け付ける:
// {f81d4fae-7dec-11d0-a765-00a0c91e6bf6}
// urn:uuid:f81d4fae-7dec-11d0-a765-00a0c91e6bf6
// f81d4fae7dec11d0a76500a0c91e6bf6
// database/sql と自動連携
db.QueryRow("SELECT id FROM users WHERE id = ?", id)

議論のハイライト

  • パッケージ名の変更: 当初は crypto/uuid として提案されたが、「暗号」の印象が強すぎるとの意見を受け、よりシンプルな uuid に変更。ユーザーは UUID を探す際に crypto/ 配下は探さないという実用的な理由による。
  • uuid.New() の包含論争: 最も多くのコメントを集めた話題。「バージョンを明示すべき」という反対意見も多かったが、google/uuid のエコシステム分析で全生成の94%がv4(または意図せずv4相当の関数)であることが示され、「アルゴリズムを気にしないユーザー向けの明確なデフォルト」として採用。将来的に better なデフォルトが登場した場合に互換性を保ちつつ切り替えられる設計。
  • NilMax の var vs func 論争: google/uuid との互換性から当初は var 採用を検討。しかし var uuid.Nil は技術的に書き換え可能(uuid.Nil[0] = 0xff)であり、ゼロから設計する場合は func が自然との結論で func Nil() UUID / func Max() UUID を採用。
  • Parse の許容フォーマット: 「RFC 9562 の正規形のみ受け付けるべき」という厳格化の意見と「google/uuid との互換性を保つべき」という意見が対立。最終的に google/uuid が受け付ける形式(ブレース付き、URN形式、ハイフンなし)をすべてサポートすることで、既存コードからの移行時に実行時の非互換性が生じないよう配慮。
  • UUID 内部構造の解析機能は意図的に除外: UUID.Version() 等の内部フィールド取得メソッドは、エコシステム分析で使用率が極めて低いこと、RFC 9562 が「UUID を不透明な値として扱うことを推奨」していること、[16]byte 型なので必要な場合はユーザーが自分でバイト操作できることを理由に除外。

関連リンク