Kotlin에서 제네릭 유형을 테스트하려고합니다.
if (value is Map<String, Any>) { ... }
그러나 컴파일러는 다음과 같이 불평합니다.
지워진 유형의 인스턴스를 확인할 수 없습니다 : jet.Map
일반 유형의 수표가 잘 작동합니다.
if (value is String) { ... }
Kotlin 0.4.68이 사용됩니다.
내가 여기서 무엇을 놓치고 있습니까?
답변
문제는 유형 인수가 지워져 런타임에 해당 String 및 Any에 대한 정보가 없기 때문에 전체 유형 Map에 대해 확인할 수 없다는 것입니다.
이 문제를 해결하려면 와일드 카드를 사용하십시오.
if (value is Map<*, *>) {...}
답변
JVM은 일반 유형 정보를 제거합니다. 그러나 Kotlin은 제네릭을 수정했습니다. 제네릭 유형 T가있는 경우 인라인 함수의 유형 매개 변수 T를 수정 된 것으로 표시하여 런타임시 확인할 수 있습니다.
따라서 다음을 수행 할 수 있습니다.
inline fun <reified T> checkType(obj: Object, contract: T) {
if (obj is T) {
// object implements the contract type T
}
}
답변
이게 더 적절한 방법이라고 생각합니다
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()
}
답변
나는 위의 해결책을 시도해 보았고, 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?>?) {
}