我正在尝试在 Kotlin 中测试泛型类型。
if (value is Map<String, Any>) { ... }
但是编译器抱怨
无法检查擦除类型的实例:jet.Map
普通类型的检查效果很好。
if (value is String) { ... }
使用 Kotlin 0.4.68。
我在这里想念什么?
我正在尝试在 Kotlin 中测试泛型类型。
if (value is Map<String, Any>) { ... }
但是编译器抱怨
无法检查擦除类型的实例:jet.Map
普通类型的检查效果很好。
if (value is String) { ... }
使用 Kotlin 0.4.68。
我在这里想念什么?
问题是类型参数被删除了,所以你不能检查完整的类型 Map,因为在运行时没有关于这些 String 和 Any 的信息。
要解决此问题,请使用通配符:
if (value is Map<*, *>) {...}
我认为这是更合适的方式
inline fun <reified T> tryCast(instance: Any?, block: T.() -> Unit) {
if (instance is T) {
block(instance)
}
}
用法
// myVar is nullable
tryCast<MyType>(myVar) {
// todo with this e.g.
this.canDoSomething()
}
另一种更短的方法
inline fun <reified T> Any?.tryCast(block: T.() -> Unit) {
if (this is T) {
block()
}
}
用法
// myVar is nullable
myVar.tryCast<MyType> {
// todo with this e.g.
this.canDoSomething()
}
JVM 删除了泛型类型信息。但是 Kotlin 已经具体化了泛型。如果你有一个泛型类型 T,你可以将内联函数的类型参数 T 标记为 reified,以便它能够在运行时检查它。
所以你可以这样做:
inline fun <reified T> checkType(obj: Object, contract: T) {
if (obj is T) {
// object implements the contract type T
}
}
我会给出一个解决方案,但我认为它很干净,有点
try{
(value as Map<String,Any>?)?.let { castedValue ->
doYourStuffHere() //using castedValue
}
}catch(e: Exception){
valueIsNotOfType() //Map<String,Any>
}
我已经尝试过上面的解决方案,tryCast<Array<String?>>
而且我想,在我列出涉及许多铸件的具体任务中,这并不是一个好主意,因为它大大降低了性能。
这是我最后做的解决方案 - 手动检查条目和调用方法,如下所示:
fun foo() {
val map: Map<String?, Any?> = mapOf()
map.forEach { entry ->
when (entry.value) {
is String -> {
doSomeWork(entry.key, entry.value as String)
}
is Array<*> -> {
doSomeWork(entry.key, (entry.value as? Array<*>)?.map {
if (it is String) {
it
} else null
}?.toList())
}
}
}
}
private fun doSomeWork(key: String?, value: String) {
}
private fun doSomeWork(key: String?, values: List<String?>?) {
}