Skip to content

GoのGenerics(ジェネリクス)とany型

GoのGenerics(ジェネリクス)とany型

Section titled “GoのGenerics(ジェネリクス)とany型”

Go 1.18で導入されたジェネリクスは、特定の型に依存しない関数やデータ型を記述することを可能にします。これにより、同じロジックを異なる型で再利用できるため、コードの重複を減らし、より安全なプログラムを構築できます。

ジェネリクスを使用しない場合

Section titled “ジェネリクスを使用しない場合”

異なる型のスライスに対して同じSum関数を実装するには、それぞれの型ごとにコードを書く必要がありました。

func SumInts(m map[string]int64) int64 {
var s int64
for _, v := range m {
s += v
}
return s
}
func SumFloats(m map[string]float64) float64 {
var s float64
for _, v := range m {
s += v
}
return s
}

comparableany といった型引数(type parameters)と型制約(type constraints)を使うことで、1つの関数で複数の型を扱えます。

// Numbersインターフェースで型をint64とfloat64に制約
type Numbers interface {
int64 | float64
}
// ジェネリックなSum関数
func Sum[T comparable, V Numbers](m map[T]V) V {
var s V
for _, v := range m {
s += v
}
return s
}
func main() {
ints := map[string]int64{"a": 1, "b": 2}
floats := map[string]float64{"c": 3.0, "d": 4.0}
fmt.Println(Sum(ints)) // int64型で呼び出し
fmt.Println(Sum(floats)) // float64型で呼び出し
}

この例では、Sum関数はint64float64のどちらのスライスでも動作し、コンパイル時に型安全性が保証されます。

Go 1.18から、interface{} の別名としてanyが導入されました。これは機能的に全く同じですが、よりシンプルで読みやすいです。

func printValue(v interface{}) {
fmt.Printf("Value: %v, Type: %T\n", v, v)
}
func printValue(v any) {
fmt.Printf("Value: %v, Type: %T\n", v, v)
}

anyは、interface{}と同じく、どんな型の値でも受け取ることができます。この変更は、interface{}が持つ「どんな型でも受け入れる」という性質をより明確に表現することを目的としています。

これらの新しい概念は、Goの型システムをより強力かつ柔軟なものにしました。ジェネリクスとany型を理解することで、より現代的で再利用性の高いGoコードを書くことができます。

Deep Research

画像

Canvas

ガイド付き学習