ジェネリクスの導入
- リストやセットのようにオブジェクトのコンテナを例に考える
Any型コンテナ
- Any型の引数にすれば何でも受け取れるようになる
- ⇔毎回ダウンキャストが必要になる
Any型コンテナ
class Container(var value: Any)
val intContainer = Container(123)
println(intContainer.value as Int)
val strContainer = Container("Hello")
println(strContainer.value as String)
特化型コンテナ
- 型の安全性は担保できるようになった
- ⇔すべての型に対応しようとしたらキリがない
特化型コンテナ
class IntContainer(var value: Int)
class StrContainer(var value: String)
.
.
.
ジェネリクスコンテナ
- 型パラメータを受け取る
- 型引数と呼ぶ
- Intで初期化した場合はvalueの型はIntになり、Stringで初期化した場合はStringになる
- キャストする必要がなくなる
ジェネリクスコンテナ
class Container<T>(var value: T)
val intContainer = Container(123)
println(intContainer.value)
val strContainer = Container("Hello")
println(strContainer.value)
ジェネリック関数
関数や、メソッド、プロパティも型パラメータを受け取ることができる
fun <T> box(value: T): Container<T> = Container(value)
val <T> T.string: String
get() = toString()
val container = box(5)
println(container.string)
Swiftはメソッド名の後ろに型パラメータを書くので順番が違う
ジェネリック制約
- 型パラメータで受け取る型に制限をかけることが可能。
-
:
以降に指定した型のサブタイプにする必要がある
interface Hoge
interface Fuga
class Foo<T>
class Bar<T: Hoge>
Foo<Hoge>() // OK
Foo<Fuga>() // OK
Bar<Hoge>() // OK
Bar<Fuga>() // NG