Как определить, является ли класс универсальным, посредством отражения в Котлине

Предположим, у нас есть следующий класс:

  data class KeyValuePair<T : Any>(
      val key: String,
      val value: T
  )

Если мы поразмышляем над следующим экземпляром этого класса: KeyValuePair("color", "amber"), первое свойство, конечно, kotlin.String, но второе свойство имеет имя типа T. Есть ли программный способ определить, что это KProperty1 является универсальным? За исключением хаков типа «имя класса не содержит точек».

Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
0
56
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Вы можете получить тип свойства, используя:

val props = KeyValuePair::class.declaredMemberProperties.first { it.name == "value" }
val returnType = props.returnType

Это вернет вам экземпляр KType, который представляет T. Однако где-то потенциально может быть определен class T, и вы не будете знать, является ли T универсальным типом или фактическим классом. Более того, универсальный тип может иметь любое имя.

Учитывая, что T в свойстве члена совпадает с T, определенным как общий тип для класса, я думаю, что один из способов ответа на ваш вопрос будет заключаться в следующем:

  1. извлечение списка универсальных типов (т.н. параметров типа) класса
  2. проверка, принадлежит ли возвращаемый тип свойства этому списку

Пример:

fun main() {
    val classTypeParams = KeyValuePair::class.typeParameters

    KeyValuePair::class.declaredMemberProperties.forEach { prop ->
        val returnType = prop.returnType
        println("${prop.name} -> ${returnType.classifier in classTypeParams}")
    }
}

который печатает:

key -> false
value -> true

Все становится немного сложнее, если вы хотите сделать то же самое с функциями, потому что:

  • функции имеют типы ввода и вывода, поэтому вам нужно искать в двух местах:
  • функции могут определять свой собственный общий тип (например, fun <T> foo(): T)

Если вы хотите узнать фактический тип T во время выполнения (например, что T на самом деле является String в вашем примере), вы не можете этого сделать из-за стирания типа — вы можете использовать параметры reified в функциях inline, но даже тогда я не думаю, что вы сможете получить то, что есть T во время выполнения

Обновлено: на самом деле вы можете получить тип времени выполнения параметра типа reified:

object Foo {
    inline fun <reified T: Any> foo(obj: T) {
        println(obj::class)
    }
}

class MyClass

fun main() {
    Foo.foo("some string") // prints kotlin.String
    Foo.foo(123) // prints kotlin.Int
    Foo.foo(MyClass()) // prints MyClass
}

это работает, большое спасибо

user14381362 01.07.2024 17:09

пожалуйста, проверьте также ответ @broot ниже, так как я думаю, что их подход лучше/проще

user2340612 01.07.2024 18:19

Нам просто нужно проверить тип свойства и, в частности, какой у него классификатор:

prop.returnType.classifier

classifier имеет тип: KClassifier и возможные подтипы (среди прочих) KClass и KTypeParameter. На данный момент это довольно просто — нам просто нужно проверить, является ли классификатор KTypeParameter:

fun main() {
    val obj = KeyValuePair("color", "amber")
    println(obj::class.declaredMemberProperties.single { it.name == "key" }.isGeneric) // false
    println(obj::class.declaredMemberProperties.single { it.name == "value" }.isGeneric) // true
}

val KProperty<*>.isGeneric get() = returnType.classifier is KTypeParameter

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