Отражение Котлина: неизвестный тип параметра

Я провожу несколько экспериментов с отражением Котлина.

Я пытаюсь получить объект отражения универсального класса с его аргументом.

На Java это было бы ParameterizedType,

Способ получить такую ​​вещь с помощью API отражения Java немного запутан: создайте анонимный подкласс обобщенного класса, а затем получите его первый параметр супертипа.

Вот пример:

@Suppress("unused") @PublishedApi
internal abstract class TypeReference<T> {}

inline fun <reified T> jGeneric() =
    ((object : TypeReference<T>() {}).javaClass.genericSuperclass as ParameterizedType).actualTypeArguments[0]

Когда я println(jGeneric<List<String?>>())печатает java.util.List<? extends java.lang.String>что логично, учитывая, что Котлина List использует сайт объявлений out Дисперсия и что типы Java не имеют понятия обнуляемости.

Теперь я хотел бы добиться такого же результата, но с API отражения Kotlin (который, конечно, содержал бы информацию об обнуляемости).

Конечно, List<String>::class не может работать, так как это дает KClass, и я ищу KType,

Тем не менее, когда я пытаюсь это:

inline fun <reified T> kGeneric() =
    (object : TypeReference<T>() {})::class.supertypes[0].arguments[0].type

Когда я println(kGeneric<List<String?>>())печатает [ERROR : Unknown type parameter 0]что вполне... ну, антиклиматично;)

Как я могу получить в Котлине KType отражающий List<String>?

1 ответ

Решение

Чтобы создать KType Например, в Kotlin 1.1 у вас есть два варианта:

  • Чтобы создать простой ненулевой тип из KClassгде класс либо не является универсальным, либо вы можете заменить все его параметры типа на звездные проекции (*), использовать starProjectedType имущество. Например, следующее создает KType представляющий ненулевой тип String:

    val nonNullStringType = String::class.starProjectedType
    

    Или следующее создает KType представляющий ненулевой тип List<*>:

    val nonNullListOfSmth = List::class.starProjectedType
    
  • Для более сложных случаев используйте createType функция. Он принимает класс, аргументы типа и должен ли тип быть обнуляемым. Аргументы типа представляют собой список KTypeProjection который просто тип + дисперсия (вход / выход / нет). Например, следующий код создает KType экземпляр, представляющий List<String>:

    val nonNullStringType = String::class.starProjectedType
    val projection = KTypeProjection.invariant(nonNullStringType)
    val listOfStrings = listClass.createType(listOf(projection))
    

    Или следующее создает тип List<String>?:

    val listOfStrings = listClass.createType(listOf(projection), nullable = true)
    

И то и другое starProjectedType а также createType определены в упаковке kotlin.reflect.full,

Мы планируем ввести возможность получения KType например, просто из параметра reified типа встроенной функции, которая может помочь в некоторых случаях, когда необходимый тип известен статически, однако в настоящее время не совсем ясно, возможно ли это без значительных накладных расходов. Итак, пока это не реализовано, пожалуйста, используйте декларации, описанные выше.

Другие вопросы по тегам