2017-04-03 65 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