TL; DR: ¿Qué es reifiedbueno para
fun <T> myGenericFun(c: Class<T>)
En el cuerpo de una función genérica como myGenericFun, no puede acceder al tipo Tporque solo está disponible en tiempo de compilación pero se borra en tiempo de ejecución. Por lo tanto, si desea utilizar el tipo genérico como una clase normal en el cuerpo de la función, debe pasar explícitamente la clase como parámetro como se muestra en myGenericFun.
Si creas un inline función con una reified T , Tse puede acceder al tipo de incluso en tiempo de ejecución y, por lo tanto, no necesita pasarlo Class<T>adicionalmente. Puede trabajar con Tcomo si fuera una clase normal, por ejemplo, es posible que desee comprobar si una variable es un ejemplo de T que se puede hacer fácilmente a continuación: myVar is T.
Tal inlinefunción con reifiedtipo se Tve de la siguiente manera:
inline fun <reified T> myGenericFun()
Como reifiedfunciona
Solo se puede usar reifieden combinación con una inlinefunción . Tal función hace que el compilador copie el código de bytes de la función en cada lugar donde se está utilizando la función (la función está "en línea"). Cuando llama a una función en línea con tipo reified, el compilador conoce el tipo real utilizado como argumento de tipo y modifica el bytecode generado para usar la clase correspondiente directamente. Por lo tanto, las llamadas se myVar is Tconvierten en myVar is String(si el argumento de tipo fuera String) en el código de bytes y en tiempo de ejecución.
Ejemplo
Echemos un vistazo a un ejemplo que muestra cuán útil reified puede ser. Queremos crear una función de extensión para Stringllamadas toKotlinObjectque intente convertir una cadena JSON en un objeto Kotlin simple con un tipo especificado por el tipo genérico de la función T. Podemos usar com.fasterxml.jackson.module.kotlinesto y el primer enfoque es el siguiente:
a) Primer enfoque sin tipo reificado
fun <T> String.toKotlinObject(): T {
val mapper = jacksonObjectMapper()
//does not compile!
return mapper.readValue(this, T::class.java)
}
El readValuemétodo toma un tipo que se supone que debe analizar JsonObject. Si tratamos de obtener elClass parámetro type T, el compilador se queja: "No se puede usar 'T' como parámetro de tipo reified. En su lugar, use una clase".
b) Solución alternativa con explícito Class parámetro
fun <T: Any> String.toKotlinObject(c: KClass<T>): T {
val mapper = jacksonObjectMapper()
return mapper.readValue(this, c.java)
}
Como solución alternativa, la ClassdeT puede hacerse un parámetro de método, que luego se usa como un argumento a readValue. Esto funciona y es un patrón común en el código genérico de Java. Se puede llamar de la siguiente manera:
data class MyJsonType(val name: String)
val json = """{"name":"example"}"""
json.toKotlinObject(MyJsonType::class)
c) La forma de Kotlin: reified
Usar una inlinefunción con reifiedparámetro de tipoT hace posible implementar la función de manera diferente:
inline fun <reified T: Any> String.toKotlinObject(): T {
val mapper = jacksonObjectMapper()
return mapper.readValue(this, T::class.java)
}
No hay necesidad de tomar el Classde Tadicionalmente,T se puede utilizar como si se tratara de una clase ordinaria. Para el cliente, el código se ve así:
json.toKotlinObject<MyJsonType>()
Nota importante: trabajar con Java
Una función en línea con reifiedtipo no se puede llamar desde el código Java .