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 
  • Dependencia circular cuando se comstack con Kotlin 1.1.2-4, pero no en 1.1.2-3
  • Java Integer.MAX_VALUE vs Kotlin Int.MAX_VALUE
  • Kotlin webview crash
  • Henetworkingar de la class abstracta con multiplicar vars en Kotlin
  • Diferenciar extensiones ambiguas en Kotlin
  • Kotlin: configuration de un boolean privado en class Java a través de una class de datos en Kotlin. ¿Por qué no puedo hacer esto?
  • java.util.logging.Logger en class probada
  • Elementos seleccionados en el menu
  • El argumento de tipo genérico no está dentro de los límites
  • La extensión de Kotlin para Android no puede resolver el "text"
  • Cómo get el valor emitido desde el primer observable