無意識理解から脱する【ジェネリクス 編】

普段TypeScriptをよく使用している私ですが、
最近業務で始めたSwiftをやっていてふと目に留まった型定義で使うこれ。
T
今となっては何も思うことなく自然に使っているのですが、
Angularを始めた頃になんだこれは!とよく思ったものです。
他にどの言語で使用されているんだろうな〜とふと疑問に思ったので、これを機におさらいしてみましょう。
ジェネリクス Generics
T
とはジェネリクス Generics (総称型)
と呼ばれるもので、
型の違うものを同じように扱えるように型を抽象化するものです。
例えばSwiftでkeyとvalueが同じ型のDictionary型を返すメソッドがあるとすると、以下のように書くことができます。
let result1 = setDictionary(key: 1, value: 100)
print(result1)
// => [1: 100]
let result2 = setDictionary(key: "id", value: "TEST000001")
print(result2)
// => ["id": "TEST000001"]
func setDictionary<T>(key: T, value: T) -> [T: T]
{
return [key: value]
}
ただし、ジェネリクスはどういった場合でも使用できるとは限りません。
例えば、ジェネリクスを使用したメソッド内で引数に対して演算子を使いたいと思っても、
Int型はできて、String型やArray型はできないため、コンパイルエラーになります。
// => Binary operator '>' cannot be applied to two 'T' operands
func choiceBigger<T>(arg1: T, arg2: T) -> T
{
if arg1 > arg2 {
return arg1
}
return arg2
}
ジェネリクスを使う言語
冒頭でもTypeScriptやSwiftで使われていると言いましたが、
他には以下のような言語で使われています。
- TypeScript
- Swift
- Java
- C#
- Kotlin
見ての通り、静的型付け言語
ばかりですね。
それぞれの言語におけるジェネリクスの使い方は参考の公式ドキュメントから参照してください。
おおまかな使い方はどの言語も共通していますので、1つの言語で覚えてしまえば問題ないように個人的に思います。
何故ジェネリクスを使うのか
ジェネリクスを使わないで先ほどのDictionary型を返すメソッドを書くとした場合。
以下のように、型が違うだけの同じ名前のメソッドを複数作らなければいけません。
let result1 = setDictionary(key: 1, value: 100)
print(result1)
// => [1: 100]
let result2 = setDictionary(key: "id", value: "TEST000001")
print(result2)
// => ["id": "TEST000001"]
func setDictionary(key: Int, value: Int) -> [Int: Int]
{
return [key: value]
}
func setDictionary(key: String, value: String) -> [String: String]
{
return [key: value]
}
しかも想定される型の数だけメソッドを生成しなければならないと。
なんとこれは面倒な!
この面倒さを解消してくれるのがジェネリクスというわけですね。
Any
を使ったらいいじゃないか。と思う人もいるかもしれませんが、
静的型付け言語でAnyを使っては意味ないですよね。
ですのでAnyを使うという発想自体はやめるように心がけましょう!←
最後に
まだジェネリクスを使用してない方には最初難しく感じるかもしれませんが、非常に便利ですので是非使って頂きたいところです。
実際私もTypeScriptではもう手放せない機能ですね←
また今回ジェネリクスを改めて調べていますと、なにやらGolangとジェネリクスに関わる記事がたくさん。。。
Golangにはジェネリクスがないのですが、それには開発者の間で色々賛否があるようで。。。
Go 2017 Survey Shows Generics and Dependency Management the Most Desired Features
ちょっと今後が気になるところですね。