如何在 Kotlin 中获取泛型参数类?

11

我需要能够在运行时确定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)
}

你的目标是JVM还是js?在JVM上除了Kotlin的refied类型之外,还有一些反射魔法,但在js后端,你只能依赖于refied类型。 - glee8e
2个回答

16

Kotlin泛型具有Java的特点,在编译时被擦除,因此在运行时,这些列表不再携带执行所需的必要信息。不过,使用具体化类型编写内联函数可以例外。例如:

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

10
您可以使用reified类型参数的inline函数来实现此目的:
inline fun <reified T : Any> classOfList(list: List<T>) = T::class

(可运行演示,包括如何在when语句中检查类型)

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

在JVM上,泛型类的类型参数在运行时被擦除,基本上无法从任意List<T>(例如作为List<T>传递给非内联函数的列表--对于每个调用,T在编译时未知,并在运行时被擦除)中检索它们。

如果您需要更多控制函数内的具体化类型参数,您可能会发现这个问答有用。

您的可运行演示缺少“:Any”在“reified T”上。 - mfulton26

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接