sql.Null[T] をGo 1.22に追加しました

Go 1.22 のリリースが近づいていますが、その中でdatabase/sqlNull[T]を追加したので紹介しておきます。

database/sql パッケージにはNullByte,NullBool,NullFloat64,NullInt64などのNullableなカラムを扱うための型が用意されているのですが、NullUInt64はありませんでした。 UInt型が標準的ではなく、driver.Valueにもuint64が含まれていないからです。

一方でMySQLはunsigned tinyint~bigint型があるのでgo-mysql-driverもuint64には対応しています。32bitまではint64で、64bitではuint64で扱うようになっています。 だからと言ってドライバー独自に NullUInt64 を提供すると、他のパッケージも同じ型を提供した時に混乱の元です。

ということで、ジェネリクスを使って sql.Null[T] を追加してもらうことにしました。

一番難しかったのはメンバーのネーミングです。例えば NullInt64 の定義は次のようになっています。

type NullInt64 struct {
    Int64 int64
    Valid bool // Valid is true if Int64 is not NULL
}

値が入っているメンバーの名前が、型の名前の先頭が大文字になったものになっているんですね。NullTime型の場合はTime time.Timeです。しかしこれに一貫性を持たせようとすると T T になるのでちょっと混乱します。

一番に思いつく名前はValueなのですが、これらの型はValuerインターフェイスを実装していて Value() メソッドを追加する必要があるので、Valueも使えません。

Valにすると、Val, Valid, Value() が並ぶことになってしまい、これもあまり良くありません。

最終的に名前は V T になりました。型名と値の名前が同じ1文字どうしなので Int64 int64 と同じくらいのペア感があり、 Val に比べると Valid, Value() との距離も少し離れたので、一番マシな選択肢だったと思います。

なお、データベースとのやりとりを目的として、Scanner/Valuerインターフェイスを実装するように設計した型なので、一般的な Optional 型の代わりに使おうとは思わないでくださいね。

このブログに乗せているコードは引用を除き CC0 1.0 で提供します。