如何在Kotlin中获得通用参数类?

paw*_*elo 9 kotlin

我需要能够在运行时告诉kotlin集合的泛型类型.我该怎么做?

val list1 = listOf("my", "list")
val list2 = listOf(1, 2, 3)
val list3 = listOf<Double>()

/* ... */

when(list.genericType()) {
    is String -> handleString(list)
    is Int -> handleInt(list)
    is Double -> handleDouble(list)
}
Run Code Online (Sandbox Code Playgroud)

pdp*_*dpi 10

Kotlin泛型共享Java在编译时被删除的特性,因此,在运行时,这些列表不再携带必要的信息来执行您所要求的操作.例外情况是,如果使用reified类型编写内联函数.例如,这将工作:

inline fun <reified T> handleList(l: List<T>) {
    when (T::class) {
        Int::class -> handleInt(l)
        Double::class -> handleDouble(l)
        String::class -> handleString(l)
    }
}

fun main() {
    handleList(mutableListOf(1,2,3))
}
Run Code Online (Sandbox Code Playgroud)

但是,内联函数会在每个调用站点进行扩展,并且会混乱堆栈跟踪,因此您应该谨慎使用它们.

但是,根据你想要达到的目标,有一些替代方案.您可以使用密封类在元素级别实现类似的功能:

sealed class ElementType {
    class DoubleElement(val x: Double) : ElementType()
    class StringElement(val s: String) : ElementType()
    class IntElement(val i: Int) : ElementType()
}

fun handleList(l: List<ElementType>) {
    l.forEach {
        when (it) {
            is ElementType.DoubleElement -> handleDouble(it.x)
            is ElementType.StringElement -> handleString(it.s)
            is ElementType.IntElement -> handleInt(it.i)
        }
    }
}
Run Code Online (Sandbox Code Playgroud)


hot*_*key 8

您可以使用inline带有reified类型参数的函数来执行此操作:

inline fun <reified T : Any> classOfList(list: List<T>) = T::class
Run Code Online (Sandbox Code Playgroud)

(runnable演示,包括如何检查when语句中的类型)

此解决方案仅限于T在编译时已知实际类型参数的情况,因为inline函数在编译时进行转换,并且编译器将其reified类型参数替换为每个调用站点的实际类型.

在JVM上,泛型类的类型参数在运行时被擦除,并且基本上没有办法从任意位置检索它们List<T>(例如,传递到非内联函数的列表,因为List<T>- T在编译时对于每个调用都不知道并在运行时擦除)

如果您需要更多地控制函数内的reified类型参数,您可能会发现此Q&A很有用.