I'm experimenting with the reflection functionality in Kotlin, but I can't seem to understand how to obtain a KType value.
Suppose I have a class that maps phrases to object factories. In case of ambiguity, the user can supply a type
parameter that narrows the search to only factories that return that type of object (or some sub-type).
fun mapToFactory(phrase: Phrase,
type: KType = Any::class): Any {...}
type
needs to accept just about anything, including Int
, which from my experience seems to be treated somewhat specially. By default, it should be something like Any
, which means "do not exclude any factories".
How do I assign a default value (or any value) to type
?
Since Kotlin 1.3.40, you can use the experimental function typeOf<T>()
to obtain the KType
of any type:
val int: KType = typeOf<Int>()
In contrast to T::class.createType()
, this supports nested generic arguments:
val listOfString: KType = typeOf<List<String>>()
The typeOf<T>()
function is particularly useful when you want to obtain a KType
from a reified type parameter:
inline fun <reified T> printType() {
val type = typeOf<T>()
println(type.toString())
}
Example usage:
fun main(args: Array<String>) {
printType<Map<Int, String>>()
// prints: kotlin.collections.Map<kotlin.Int, kotlin.String>
}
Since this feature is still in experimental status, you need to opt-in with @UseExperimental(ExperimentalStdlibApi::class)
around your function that uses typeOf<T>()
. As the feature becomes more stable (possibly in Kotlin 1.4), this can be omitted. Also, at this time it is only available for Kotlin/JVM, not Kotlin/Native or Kotlin/JS.
See also:
From your description, sounds like your function should take a KClass
parameter, not a KType
, and check the incoming objects with isSubclass
, not isSubtype
.
Types (represented by KType
in kotlin-reflect
) usually come from signatures of declarations in your code; they denote a broad set of values which functions take as parameters or return. A type consists of the class, generic arguments to that class, and nullability. The problem with types at runtime on JVM is that because of erasure, it's impossible to determine the exact type of a variable of a generic class. For example if you have a list, you cannot determine the generic type of that list at runtime, i.e. you cannot differentiate between List<String>
and List<Throwable>
.
To answer your initial question though, you can create a KType
out of a KClass
with createType()
:
val type: KType = Any::class.createType()
Note that if the class is generic, you need to pass type projections of generic arguments. In simple cases (all type variables can be replaced with star projections), starProjectedType
will also work. For more info on createType
and starProjectedType
, see this answer.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With