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 
  • agregar fragment en la actividad del fragment no funciona en Pixel XL versión de Android 8.0.0
  • Cómo integrar Admob Native Advanced Ads usando Kotlin - Android
  • Kotlin: instancia única de una class no singleton?
  • Botón de dialog Anko titile
  • TornadoFX: Type-Safe CSS con otras bibliotecas
  • Cómo usar fragments con kotlin
  • Android ProgressBar indeterminado no aparece
  • Llamada asincrónica para cada elemento dentro de una colección
  • Objetos complementarios: ¿desea Android registrarlos como actividades (?)
  • Kotlin Pass en un tipo que implementa una interfaz parametrizada
  • Kotlin Kapt: java.lang.IllegalStateException: endPosTable ya está configurado