[generic-programming] Kotlin에서 제네릭 유형을 어떻게 확인할 수 있습니까?

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?>?) {

}


답변