Open8
Goのジェネリックとは何ぞや
Generics とは
Generics:「相称性」
データの方に束縛されず、型そのものをパラメータ化して扱うことができる。
型を抽象化してコードの再利用性を向上させつつ、静的型付け言語の型安全性を維持できる
参考:https://zenn.dev/nobishii/articles/type_param_intro
要するに
同じ処理だけど、引数の型が違うよっていう処理を一つの関数にまとめちゃうよっていう便利君。
Goにジェネリックがあれば…みたいに言われてたらしく、それで実装したっぽい
Goのジェネリクスの基本原則
- 「関数」と「型」は「型パラメータ」を持つことができる
- 「型パラメータ」の満たす性質は「インターフェース型」を「型制約」として使うことで表す
func main() {
fmt.Println(f([]MyInt{1, 2, 3, 4}))
// Output:
// [1 2 3 4]
}
// fは型パラメータを持つ関数
// Tは型パラメータ
// インタフェースStringerは、Tに対する型制約として使われている
func f[T Stringer](xs []T) []string {
var result []string
for _, x := range xs {
// xは型制約StringerによりString()メソッドが使える
result = append(result, x.String())
}
return result
}
type Stringer interface {
String() string
}
type MyInt int
// MyIntはStringerを実装する
func (i MyInt) String() string {
return strconv.Itoa(int(i))
}
つまり、何ができるようになったのか
type Stringer interface {
String() string
}
func f(xs []Stringer) []string {
// いい感じの処理
}
type MyInt int
// MyIntはStringerを実装する
func(i MyInt) String() string {
return strconv.Itoa(int(i))
}
# こいつを実行してみると、できない。
xs := []MyInt{0,1,2}
f(xs) // fは[]Stringerを受け付ける
こんな感じでMyIntをStringerとして実装(文字列で返却される形)
関数f
はstringを引数としているが、MyIntはintなのでエラー
このとき、関数fを以下にする
func f(xs interface{}) {
fmt.Println(xs)
}
そしたら動く。でも、interfaceを引数にしているので、型が間違っていても関数が走ってしまう。
つまりこうゆうことや
package main
import (
"fmt"
"strconv"
)
func main() {
fmt.Println(f([]MyInt{1, 2, 3, 4}))
fmt.Println(f([]MyString{"a","b"}))
// Output:
// [1 2 3 4]
}
// fは型パラメータを持つ関数
// Tは型パラメータ
// インタフェースStringerは、Tに対する型制約として使われている
func f[T Stringer](xs []T) []string {
var result []string
for _, x := range xs {
// xは型制約StringerによりString()メソッドが使える
result = append(result, x.String())
}
return result
}
type Stringer interface {
String() string
}
type MyInt int
type MyString string
func (s MyString) String() string{
return string(s)
}
// MyIntはStringerを実装する
func (i MyInt) String() string {
return strconv.Itoa(int(i))
}
で、どんな時に使うんやろうな
-
interface{}
の代わりに使われるだろうな -
yml
とかのファイル生成に便利そう- 型の指定がないから