背景
Go1.27から標準ライブラリにuuidが追加されました。
これまでgoogle/uuid等のサードパーティのライブラリを利用していましたが標準ライブラリだけでuuidを扱えるようになりました。
そこで、今回はUUIDの基本的な仕組み、Go1.27の採用背景、既存ライブラリとの違いについてまとめました。
目次
UUIDとは
UUIDとは、"Universally Unique Identifier"の略で、データを区別するために利用される128ビットの識別子のことです。
RFC9562でv1~v8まで定義されています。
フォーマットは全てのバージョンで共通しており、
xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
8-4-4-4-12のようになっています。
特に世の中で広く利用されているv4とv7の違いにフォーカスします。
特徴
| 項目 | UUID v4 | UUID v7 |
|---|---|---|
| 生成方式 | ランダム | タイムスタンプ + ランダム |
| 時系列順 | 保証されない | おおむね時系列順 |
| 生成時刻の推測 | 不可 | 可能 |
| 一意性 | ランダム性に依存 | 時刻とランダム性に依存 |
| 主な用途 | ランダムな識別子 | DBの主キー、時系列データ |
内訳
| 項目 | UUID v4 | UUID v7 |
|---|---|---|
| タイムスタンプ | 0ビット | 48ビット |
| ランダム部分 | 122ビット | 最大74ビット(一部カウンター等にも利用可能) |
| バージョン | 4ビット | 4ビット |
| バリアント | 2ビット | 2ビット |
| 合計 | 128ビット | 128ビット |
具体例
# v4
550e8400-e29b-41d4-a716-446655440000
↑ ↑
v4 バリアント
ランダム値:122ビット
バージョン:4ビット
バリアント:2ビット
# v7
01941f2a-7c00-7b8e-9d12-345678abcdef
└───────────┘ ↑ ↑
タイムスタンプ v7 バリアント
48bit
タイムスタンプ:48ビット
ランダム等:74ビット
バージョン:4ビット
バリアント:2ビット
v4は完全ランダムであるのに対して、v7は時系列データを保有しているところが大きな違いになります。
ランダム性を求める場合はv4, 時系列ソートやDBのインデックス効率を求める場合はv7といった使い分けが出来そうです。
なお、v7についてはランダム部分もカスタマイズ可能な点が特徴です。
サブミリ秒以上の精度を求められる要件の場合にはランダム部分を利用して、より詳細なタイムスタンプやカウンターをセットすることが出来ます。
ランダム部分を減らしすぎると、衝突や推測のリスクが増えるため、カスタマイズはデータの要件次第になります。
Go1.27で標準ライブラリで組み込まれた背景
Goには、既存のコードが将来のバージョンでも動作することを保証する「Go 1 Compatibility Promise」という後方互換性の方針があります。
これはGoを利用する開発者にとって大きなメリットですが、一方でGo本体の開発者にとっては、新しい機能を追加する際の制約にもなります。一度標準ライブラリに追加したAPIは、基本的に削除や破壊的変更ができないため、採用には慎重な判断が求められます。
実際、UUIDの標準ライブラリへの追加は2018年にも提案されていましたが、当時はサードパーティ製ライブラリで十分対応できるとして見送られていました。
しかし、その後もUUIDの利用は広がり、github.com/google/uuid はGoのエコシステムで2番目に多くインポートされるパッケージとなりました。
こうした普及状況に加え、UUIDを扱う共通の型を標準ライブラリで提供することで、異なるライブラリ間の相互運用性を高められることが採用の大きな理由となったようです。
利用者としても、google/uuid は十分に実績のあるライブラリですが、標準ライブラリであれば外部依存を減らせるだけでなく、Go本体の互換性保証のもとで長期的に利用できるという安心感があります。
単に便利なライブラリが標準化されたというだけでなく、Goのエコシステム全体でUUIDを共通して扱えるようになったことに意味があると感じました。
ソースコード比較
google/uuidの型(抜粋)
// Copyright 2018 Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package uuid
import (
"bytes"
"crypto/rand"
"encoding/hex"
"errors"
"fmt"
"io"
"strings"
"sync"
)
// A UUID is a 128 bit (16 byte) Universal Unique IDentifier as defined in RFC
// 4122.
type UUID [16]byte
...
標準ライブラリのuuid(抜粋)
// Copyright 2026 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package uuid provides support for generating and manipulating UUIDs.
//
// See [RFC 9562] for details.
//
// Random components of new UUIDs are generated with a
// cryptographically secure random number generator.
//
// UUIDs may be generated using various algorithms.
// The [New] function returns a new UUID generated using
// an algorithm suitable for most purposes.
//
// [RFC 9562]: https://www.rfc-editor.org/rfc/rfc9562.html
package uuid
import (
"bytes"
"cmp"
"crypto/rand"
"encoding/binary"
"encoding/hex"
"errors"
"sync"
"time"
)
// A UUID is a Universally Unique Identifier as specified in RFC 9562.
//
// UUIDs are comparable, such as with the == operator.
type UUID [16]byte
...
パッケージ名・型名・内部構造はいずれも同じですが、Goでは異なるパッケージで定義された名前付き型は別の型として扱われます。
型変換が毎回必要になるため、同じプロジェクト内では統一する方が良さそうです。
実務での利用
現在Go1.27のuuidではv4とv7をサポートしています。
メンテナンスの恩恵を受けるために既存システムで上記にバージョンを採用している場合は、移行の検討をしてみても良いかもしれません。
確認作業はありますが、ソースコードも似ているので移行のコストはそんなに高くないんじゃないかなぁと思っています。
さいごに
Go系のカンファレンスでGo1.27リリースの概要を何度か聞いたので、復習のため技術ブログを執筆しました。uuidのバージョンの違いやgo1.27で導入されたuuidについて理解することが出来てよかったです。
こういった標準ライブラリの導入によって逆にサードパーティで利用していたライブラリのメンテナンスの優先度が落ちてしまうのも個人的に気になります。google製のuuidはどれくらいの頻度でメンテナンスするんでしょうか...?
とはいえ、標準にした方が良いと思うので順次移行していきたいなと思っています。
参考文献