Inferir un tipo genérico de Mapa en Kotlin

Considere un método Java que infiere su tipo en class Java de la siguiente manera:

public <T> T readJson(Class<T> c) throws IOException { 

Esto permite hacer algo como esto:

 Map<String, String> map = foo.readJson(Map.class); 

En java advertirá sobre el lanzamiento sin marcar, pero funcionará correctamente. Sin embargo, en Kotlin, esto no será tan fácil, uno podría intentar usar:

 foo.readJson(Map::class.java) 

Sin embargo, si se requiere Map<String, String> , no funcionará:

 Type inference failed. Expected type mismatch. requinetworking Map<String, String> found Map<*, *>! 

También traté de definir una interfaz StringMap:

 interface StringMap : Map<String, String> 

Sin embargo, eso tampoco funciona, dará lugar a excepciones como esta:

 Cannot cast ...LinkedTreeMap to ...StringMap 

¿Cuál sería la forma correcta de hacer esto?

Kotlin no tiene nada como los types crudos de Java (que se dejaron en Java para compatibilidad con versiones anteriores), y el sistema de types por lo tanto no permite este tipo de asignaciones no verificadas implícitamente ( proyecciones en estrella , el concepto más cercano a types crudos en Kotlin, retener tipo de security).

Puede hacer un lanzamiento desactivado en Map<String, String> , expresando así que está al tanto de una posible discrepancia de tipo en el time de ejecución:

 @Suppress("UNCHECKED_CAST") val result = foo.readJson(Map::class.java) as Map<String, String> 

Puede suprimir la advertencia de conversión sin marcar para un scope más amplio que una sola statement.

Una mejora natural de esta solución es escribir una function util para ocultar el molde sin marcar:

 @Suppress("UNCHECKED_CAST") inline fun <reified T: Any> JsonReader.readJson(): T { val result = readJson(T::class.java) return result as T } 

Esta solución utiliza una function en línea con un parámetro de tipo reificado : la function se transforma y sustituye en cada uno de sus sitios de llamadas, con T reemplazado por el tipo especificado (o inferido) en el momento de la compilation.

Ejemplos de uso:

 val map = jsonReader.readJson<Map<String, String>>() 

 fun processMap(map: Map<String, String) { /* ... */ } processMap(jsonReader.readJson()) // Map<String, String> is infernetworking for this call 
  • Error de segmentación de Android Emulator 6824
  • Cómo escribir un método de extensión genérico en Kotlin?
  • Usando RxJava con Handler, restablece Message.what value
  • Firma de tipo para la function Kotlin con parameters pnetworkingeterminados
  • Referencia no resuelta de una function de extensión de Kotlin en la construcción de Gradle
  • La mejor manera de manejar ese escenario donde "smart cast es imposible"
  • Incluyendo la biblioteca de reflexión en un file jar generado por kotlinc
  • ¿Cuál es la diferencia entre Foo :: class.java y Foo :: javaClass?
  • java.lang.NoClassDefFoundError: kotlin / jvm / internal / Intrinsics en libgdx
  • Configuración de Kotlin para Gradle sin asistencia de IDE: las classs de Kotlin no llegan a classpath
  • Dokka javadoc jar no funciona con Intellij IDE