我需要能够在运行时告诉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)
}
答案 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有用。