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

时间:2017-04-03 12:36:07

标签: 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)
}

2 个答案:

答案 0 :(得分:8)

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))
}

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

根据您尝试实现的目标,还有一些替代方案。您可以使用密封类在元素级别实现类似的功能:

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)
        }
    }
}

答案 1 :(得分:7)

您可以使用inline functions with reified type parameters执行此操作:

inline fun <reified T : Any> classOfList(list: List<T>) = T::class

(runnable demo, including how to check the type in a when statement)

此解决方案仅限于在编译时已知T的实际类型参数的情况,因为inline函数在编译时被转换,并且编译器替换它们的reified在每个呼叫站点输入具有真实类型的参数。

在JVM上,泛型类的类型参数在运行时被擦除,并且基本上没有办法从任意List<T>中检索它们(例如,作为{{1}传递给非内联函数的列表} - List<T>在编译时不为每个调用所知,并在运行时被删除)

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