Goジェネリクスの型制約で迷わないための実務ガイド
🚀 Goジェネリクスの型制約で迷わないための実務ガイド
📝 はじめに
Go 1.18 以降、ジェネリクスが導入されました。
便利になった一方で「型制約(type constraint)」の書き方で迷う人は多いと思います。
特に混乱しやすいのが次の3つです:
-
~intと~Hogeの違い -
type Hoge = intとtype Hoge intの違い - 「Hogeを基にした型だけ」を許可したいときのマーカーインターフェースの使い方
この記事では、それぞれをコード例・解説を交えながら整理し、最後に 「実務ではどう選べばいいか?」 の判断指針をまとめます。
📖 Go ジェネリクスと型制約の基本
型パラメータ
Goのジェネリクスは「関数や型にパラメータ化された型」を渡せる仕組みです。
func PrintAll[T any](values []T) {
for _, v := range values {
fmt.Println(v)
}
}
-
Tが型パラメータ -
anyは「どんな型でもOK」という制約
型制約(constraint)
型パラメータには「どんな型が渡せるか」を制約できます。
例えば「整数っぽい型だけ」を許可したい場合:
type Integer interface {
int | int64 | uint
}
func Sum[T Integer](a, b T) T {
return a + b
}
-
Integerが制約インターフェース -
int | int64 | uintが「型集合」
型集合(type set)
制約インターフェースは「その型が取り得る集合」を定義します。
-
any→ すべての型 -
int | string→ int か string -
~int→ 基底型が int のすべての型 -
~Hoge→ Hoge がエイリアスの場合のみ有効
📌 1. ~int と ~Hoge の違い
~int
「基底型が int のすべての型」を許可します。
type MyInt int
type Another int
type IntFamily interface {
~int
}
👉 OK: int, MyInt, Another
~Hoge
Hoge を
エイリアス(type Hoge = int)で定義した場合のみ有効です。
type Hoge = int
type Fuga Hoge
type HogeFamily interface {
~Hoge
}
👉 OK: int, Hoge, Fuga
👉 NG: type Hoge int の場合はエラーになる
📌 2. type Hoge = int と type Hoge int の違い
型定義(defined type)
type Hoge int
- 新しい型を作る
-
intとは別物 - 制約では
~intを使う
型エイリアス(alias)
type Hoge = int
-
intの別名 -
~Hogeで制約を書ける - 実際の挙動は
intと完全に同じ
📌 3. マーカーインターフェースで制御する
~int だと「全部の int 系」を許可してしまいます。
もし Piyo のように int
ベースだけど対象外にしたい場合はマーカーを使います。
type Hoge int
type Fuga Hoge
type Piyo int // ← 除外したい
type HogeFamily interface {
~int
isHogeFamily()
}
// Hoge 系の型だけマーカーを実装
func (Hoge) isHogeFamily() {}
func (Fuga) isHogeFamily() {}
👉 こうすることで「Hoge 系だけ」をジェネリクスの対象にできます。
🙅♂️ よくある誤解と落とし穴
-
type Hoge intとtype Hoge = intは同じではない
→ 前者は「新しい型」、後者は「別名」 -
~Hogeは常に使えるわけではない
→ エイリアス型のときだけ -
マーカーインターフェースは魔法ではない
→ 型側にisHogeFamily()を実装しないと効力がない
📊 実務での選び方(まとめ)
| やりたいこと | 選ぶべき書き方 | 実務での推奨度 |
|---|---|---|
| int 系全般を許可したい | ~int |
✅ よく使う |
| 特定系列だけ許可したい | マーカーインターフェース | 🛠 必要に応じて |
| int と完全に同一扱いしたい |
type Hoge = int + ~Hoge
|
⚠️ レアケース |
🎯 結論(実務で迷わない指針)
- ✅ まずは
type Hoge int+~intを基本にする - ⚠️
~Hogeは特殊用途なので実務で出番はほぼない - 🛠 系列を制御したいときだけマーカーを使う
👉 迷ったら「type Hoge int + ~int」でOK。
特殊な場面に遭遇したときだけ「マーカー」や「エイリアス」を検討すれば十分です。
この記事を読めば、ジェネリクスの型制約で迷ったときの判断基準がすぐに思い出せるはずです。
ぜひ現場での実装に役立ててください。
Discussion