2016-03-27 15 views
14

Korzystanie reified type parameters, można napisać funkcję inline, który działa z parametrem typu poprzez odbicie w czasie wykonywania:Jak uzyskać rzeczywiste argumenty typu reifikowanego parametru ogólnego w Kotlin?

inline fun <reified T: Any> f() { 
    val clazz = T::class 
    // ... 
} 

Ale kiedy f jest wywoływana z parametrem, który sam jest rodzajowy klasy, wydaje się, że nie ma mowy aby uzyskać rzeczywiste argumenty typu poprzez T::class:

f<List<Integer>>() // T::class is just kotlin.collections.List 

Czy istnieje sposób, aby uzyskać rzeczywiste argumenty type reified generycznych poprzez odbicie?

+0

wymiana ** ** Każdy z odpowiedni interfejs, i pracować z interfejsem :) –

Odpowiedz

22

Z powodu type erasure, rzeczywiste argumenty ogólne nie mogą zostać uzyskane za pomocą tokena klasy generycznej za pomocą T::class. Różne obiekty klasy muszą mieć ten sam token klasy, dlatego nie może zawierać rzeczywistych argumentów ogólnych.

Ale istnieje technika o nazwie super type tokens, która może podać rzeczywiste argumenty typu w przypadku, gdy typ jest znany w czasie kompilacji (dotyczy to reifikowanych generycznych w Kotlin z powodu wstawiania).

Podstęp polega na tym, że kompilator zachowuje rzeczywiste argumenty typu dla nie ogólnej klasy wywodzącej się z klasy ogólnej (wszystkie jej wystąpienia będą miały te same argumenty, dobre objaśnienie, here). Są one dostępne przez instancję clazz.genericSuperClass.actualTypeArguments instancji Class<*>.

Biorąc pod uwagę wszystko, co można napisać klasy util tak:

abstract class TypeReference<T> : Comparable<TypeReference<T>> { 
    val type: Type = 
     (javaClass.genericSuperclass as ParameterizedType).actualTypeArguments[0] 

    override fun compareTo(other: TypeReference<T>) = 0 
} 

wyjaśnione Jackson TypeReference który używa tego samego podejścia. Moduł Jacksona Kotlina uses it dotyczący reifikacji generyków.

Następnie w funkcji rolkach z A reified generycznych TypeReference potrzeby na podklasy (e object expression się go), a następnie jego type mogą być użyte.

przykład:

inline fun <reified T: Any> printGenerics() { 
    val type = object : TypeReference<T>() {}.type 
    if (type is ParameterizedType) 
     type.actualTypeArguments.forEach { println(it.typeName) } 
} 

printGenerics<HashMap<Int, List<String>>>():

java.lang.Integer 
java.util.List<? extends java.lang.String>