Declare the generic parameter of the function type in a way that allows both for types with a null value and using this type parameter to declare `KClass <T>`
KClass defined as public interface KClass<T : Any> : KDeclarationContainer, KAnnotatedElement, KClassifier
This is complicated because there String?must be a class KClass<String>, but it cannot be obtained.
Given the following three examples below (they should all do the same job), 1 of them does not compile, and the rest return the same type of runtime.
inline fun <reified T> test1(): Any = T::class
inline fun <reified T: Any> test2(): KClass<T> = T::class
inline fun <reified T> test3(): KClass<T> = T::class // does not compile
test1<String?>() // class kotlin.String
test1<String>() // class kotlin.String
test2<String?>() // does not compile
test2<String>() // class kotlin.String
The goal of the question is to ask: how can I get runtime test1behavior with compile-time behavior (and security) test2?
EDIT: One last addition to the question is another example that demonstrates the problem of getting a class of type NULL.
inline fun <reified T> test4() {
val x = T::class // compiles, implied type of x is KClass<T>
val y: KClass<T> = T::class // does not compile with explicit type of KClass<T>
}
, , :
class OutputContract<T>(
private val output: () -> T,
val outputType: KClass<T> // ERROR!
) {
fun invoke(): T {
return output()
}
}
inline fun <reified T> output(noinline output: () -> T): OutputContract<T> {
return OutputContract(output, T::class)
}
KClass<T>, T::class, . , Any . KClass<T> KClass<Any>, ( , , ). , , , , , .
. myFun<String?>(), , , , , . , , . , , : " ?"
, T? , , . : T: Any , , , .
, :
, , , NULL, reified :
// call site, any return type nullable or not val something: String? = doSomething() // function inline fun <reified T: Any> doSomething(): T? { val x: KClass<T> = T::class // ... }, :
// call site, any parameter type nullable or not val param: String? = "howdy" doSomethingElse(param) // function inline fun <reified T: Any> doSomethingElse(parm: T?) { val x: KClass<T> = T::class // ... }( ):
// call site, any non-nullable generic parameter doSomething<String>() // function inline fun <reified T: Any> doSomethingElse() { val x: KClass<T> = T::class // ... }, ( ????):
// call site: whatever you want it to be // function: inline fun <reified T> test4() { val x = T::class // compiles, implied type of x is KClass<T> val y: KClass<*> = T::class KClass<T> }xy, /KClass.
, , , . , T? , ?
<T: Any> T? .
, NULL, output, KClass:
class OutputContract<T: Any>(private val output: () -> T?, val outputType: KClass<T>) {
fun invoke(): T? {
return output()
}
}
inline fun <reified T: Any> output(noinline output: () -> T?): OutputContract<T> {
return OutputContract(output, T::class)
}
- nullability, , null, Kotlin . invoke , . , , T, KClass, KClass<*> , KClass. , . , KClass, . KClass , , , KType.
: , , , . , "" .
Nullability KType KClass, KType . , KT-15992. , , .
reified KClass, , KClass , .
, , KType, , T::class.createType(...), . reified T, , :
inline fun <reified T : Any?> sample() {
println("Is nullable: ${isNullable<T>()}")
}
inline fun <reified T : Any?> isNullable(): Boolean {
return null is T
}
fun main(args: Array<String>) {
sample<String?>()
sample<String>()
}
// Is nullable: true
// Is nullable: false
, KType.
:
KType . Klutter, Klutter 2.5.3, .
val nullableString = reifiedKType<String?>()
println(nullableString.isMarkedNullable) // true
val nonNullableString = reifiedKType<String>()
println(nonNullableString.isMarkedNullable) // false
