2017-04-03 68 views
2

我需要能够在运行时告诉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) 
} 
+0

您是针对JVM还是js?在JVM上,除了kotlin反射类型之外,还有一些反射魔法,但在js后端,所有你可以依赖的都是重写类型。 – glee8e

回答

4

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

您可以使用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类型参数替换为ea处的实型ch呼叫站点。

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

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

+0

您的可运行演示缺少“实名T”上的“:任何”。 – mfulton26

+1

@ mfulton26,谢谢,修正了它。 – hotkey