TL; DR: ¿Qué es reified
bueno para
fun <T> myGenericFun(c: Class<T>)
En el cuerpo de una función genérica como myGenericFun
, no puede acceder al tipo T
porque 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
, T
se puede acceder al tipo de incluso en tiempo de ejecución y, por lo tanto, no necesita pasarlo Class<T>
adicionalmente. Puede trabajar con T
como 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 inline
función con reified
tipo se T
ve de la siguiente manera:
inline fun <reified T> myGenericFun()
Como reified
funciona
Solo se puede usar reified
en combinación con una inline
funció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 T
convierten 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 String
llamadas toKotlinObject
que 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.kotlin
esto 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 readValue
mé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 Class
deT
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 inline
función con reified
pará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 Class
de T
adicionalmente,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 reified
tipo no se puede llamar desde el código Java .