Kotlin Generics and nullable Class type

2019-09-15 04:46发布

问题:

How do I handle a nullable generics Class type in Kotlin?

Example function with generics:

fun <I> calculateStuff(valueType: Class<I>, defaultValue: I): I {
    // do some work

    return defaultValue;
}

Here is a calling function (note the 2nd param for calculateStuff(...))

fun doStuff() {
    // works fine!
    val myVar1 = calculateStuff(String::class.java, "")

    // FAIL (null is not accepted... Error: "Cannot infer type parameter I in....")
    val myVar2 = calculateStuff(String::class.java, null)
}

Work-around (change return type to I? AND defaultValue to I?):

fun <I> calculateStuff(valueType: Class<I>, defaultValue: I?): I? {
    return defaultValue;
}

Preferred method, but does not seemed supported by Kotlin (note "String?::class.java"):

val myVar2 = calculateStuff(String?::class.java, null)

I really want to be able to send to the method (calculateStuff(...)) the return type, and if it can be null, as the first parameter... that way I ONLY have to null-check the return value if I pass a nullable Class in the first param.

Is this possible to do in Kotlin?

回答1:

You need to change Class<I> to Class<out I>:

fun <I> calculateStuff(valueType: Class<out I>, defaultValue: I): I {
    return defaultValue;
}

You can also do this using reified type parameters:

inline fun <reified I> calculateStuff(defaultValue: I): I {
    // do some work

    return defaultValue;
}

Usage:

val myVar1 = calculateStuff("")             // myVar1 is String
val myVar2 = calculateStuff<String?>(null)  // myVar2 is String?


回答2:

Since there is no way to specify nullable classes as you discovered, your premise of limiting it by the first variable is not possible.

What is possible is to limit it by the nullability of the second variable by adding a second generic parameter:

fun <I, NI: I> calculateStuff(valueType: Class<NI>, defaultValue: I): I {
    // do some work

    return defaultValue;
}

val myVar2 = calculateStuff(String::class.java, null as String?) will now compile.

The reason this works is because in the kotlin type system, T is a subclass of T? so any non-nullable value is an acceptable value for a nullable type.



标签: kotlin