0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Golang Generics について

Posted at

概要

Golang での Generics に関する知見をまとめた記事になります。

Generics とは?

ジェネリック(総称あるいは汎用)プログラミング)は、具体的なデータ型に直接依存しない、抽象的かつ汎用的なコード記述を可能にするコンピュータプログラミング手法である。

Golang では1.18からGenericsを利用できるようになりました。

引用元

比較

公式のドキュメントを元にGenerics有無のソースコードの比較と書き方を確認します

Generics を利用しないソースコード

main.go
package main

import "fmt"

func main() {
    // Initialize a map for the integer values
    ints := map[string]int64{
        "first":  34,
        "second": 12,
    }

    // Initialize a map for the float values
    floats := map[string]float64{
        "first":  35.98,
        "second": 26.99,
    }

    fmt.Printf("Non-Generic Sums: %v and %v\n",
        SumInts(ints),
        SumFloats(floats))
}

// SumInts adds together the values of m.
func SumInts(m map[string]int64) int64 {
    var s int64
    for _, v := range m {
        s += v
    }
    return s
}

// SumFloats adds together the values of m.
func SumFloats(m map[string]float64) float64 {
    var s float64
    for _, v := range m {
        s += v
    }
    return s
}

仮にint64, float64以外の型を追加する場合に新たな関数を追加する必要がある。
Genericsを用いた場合、上記の問題を回避できる(汎用的な関数を作成できる)。

Generics を利用したソースコード

main.go
package main

import "fmt"

type Number interface {
    int64 | float64
}

func main() {
    // Initialize a map for the integer values
    ints := map[string]int64{
        "first": 34,
        "second": 12,
    }

    // Initialize a map for the float values
    floats := map[string]float64{
        "first": 35.98,
        "second": 26.99,
    }

    fmt.Printf("Generic Sums: %v and %v\n",
        SumIntsOrFloats[string, int64](ints),
        SumIntsOrFloats[string, float64](floats))

    fmt.Printf("Generic Sums, type parameters inferred: %v and %v\n",
        SumIntsOrFloats(ints),
        SumIntsOrFloats(floats))

    fmt.Printf("Generic Sums with Constraint: %v and %v\n",
        SumNumbers(ints),
        SumNumbers(floats))
}

// SumIntsOrFloats sums the values of map m. It supports both floats and integers
// as map values.
func SumIntsOrFloats[K comparable, V int64 | float64](m map[K]V) V {
    var s V
    for _, v := range m {
        s += v
    }
    return s
}

// SumNumbers sums the values of map m. Its supports both integers
// and floats as map values.
func SumNumbers[K comparable, V Number](m map[K]V) V {
    var s V
    for _, v := range m {
        s += v
    }
    return s
}

Type Parameters

関数の引数の前に[]内に記述され、型を記述できます。
現状はanycomparableがビルドインされていて、上記のソースコードではcomparableが定義されています。
comparableとは、型の値に == および != 演算子を使用できるようにする制約です。
参考:Type parameters

Type Sets

以下の様に方パラメータを制約したい時にインターフェースを定義することができる。

type Number interface {
    int64 | float64
}

SumIntsOrFloatsSumNumbers関数の引数は実質同じだと考えられるが、引数が多数存在する場合はインターフェースを定義した方が可読性が上がりそう。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?