Kotlin

Kotlinチートシート: Generics編

元の記事 → Swift to Kotlinチートシート

functionのGenerics

fun <T> get(arg: T): T {
   return arg
}

classのGenerics

class Bar<T> {}

Generics型の制約

class Bar<T: View> {}

複数制約を設ける場合は where で書く。

class Bar<T> where T: View, T: TypeCode {}

何も制約を設けない場合は Any? 扱い。
以下のケースではKClassのTがnullを許容しないので、少なくとも optional を外して、T: Anyにしないとコンパイルが通らない。

fun <T: Any> get(type: KClass<T>) : T {
    return type.java.newInstance()
}

Generics型のインスタンス化

Generics型のインスタンス化はできないっぽい。
以下のようにTypeを受け取ってオブジェクトを作ることはできる。

fun <T: Any> get(type: KClass<T>) : T {
    return type.java.newInstance()
}

Genericsのワイルドカード

Javaで言う Class<?> は アスタリスクを使って Class<*>のように書く。
このアスタリスクはout Any?を表す。
out なのでGenerics型は戻り値にしか使えない。

Generics Typeからクラスオブジェクトを取得する

T::class のように Genericsの型からクラスオブジェクトを取得するのは、基本的に無理。

inline fun <reified T>foo() {
    System.out.println(T::class)
}

上記のようにfunction を inline にしてGenericsの型に reified をつけるとクラスオブジェクトを取得できるが、inlineのファンクションは色々と制限があり、使うのが難しい場合がある。

また、今のところクラスに指定したGenericsパラメータからはクラスオブジェクトを取得する術がないっぽい。

class Foo<T> {
   fun test() {
      // ここで T::class を使うすべがない
   }
}

declaration-site variance

Genericsパラメーターを制約付きWildcardにしたい場合、型の前に out を記載する。

Java
List<? extends Number> b = a;
Swift
val b: ArrayList<out Number> = a

詳細は以下に書いているがまだちゃんと理解できていない。
https://kotlinlang.org/docs/reference/generics.html#variance