Предположим, у нас есть следующий класс:
data class KeyValuePair<T : Any>(
val key: String,
val value: T
)
Если мы поразмышляем над следующим экземпляром этого класса: KeyValuePair("color", "amber")
, первое свойство, конечно, kotlin.String
, но второе свойство имеет имя типа T. Есть ли программный способ определить, что это KProperty1
является универсальным? За исключением хаков типа «имя класса не содержит точек».
Вы можете получить тип свойства, используя:
val props = KeyValuePair::class.declaredMemberProperties.first { it.name == "value" }
val returnType = props.returnType
Это вернет вам экземпляр KType
, который представляет T
. Однако где-то потенциально может быть определен class T
, и вы не будете знать, является ли T
универсальным типом или фактическим классом. Более того, универсальный тип может иметь любое имя.
Учитывая, что T
в свойстве члена совпадает с T
, определенным как общий тип для класса, я думаю, что один из способов ответа на ваш вопрос будет заключаться в следующем:
Пример:
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
}
пожалуйста, проверьте также ответ @broot ниже, так как я думаю, что их подход лучше/проще
Нам просто нужно проверить тип свойства и, в частности, какой у него классификатор:
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
это работает, большое спасибо