unit type reified pass new generics kotlin kotlin-reified-type-parameters

generics - type - new in kotlin



¿Cómo funciona la palabra clave reified en Kotlin? (1)

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 erased 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 .

Sin embargo, si crea una función en inline con una T reificada , se puede acceder al tipo de T incluso en tiempo de ejecución y, por lo tanto, no necesita pasar la Class<T> adicionalmente. Puede trabajar con T como si fuera una clase normal, por ejemplo, es posible que desee comprobar si una variable es una instancia de T , lo que puede hacer fácilmente: myVar is T

Tal función en inline con reified type T ve de la siguiente manera:

inline fun <reified T> myGenericFun()

Cómo funciona reified

Solo puede usar reified en combinación con una función en inline . Dicha 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, llamadas como myVar is T convierten en myVar is String (si el argumento de tipo fuera String ) en el myVar is String y en tiempo de ejecución.

Ejemplo

Echemos un vistazo a un ejemplo que muestra cuán útil puede ser la reified . Queremos crear una función de extensión para String llamada toKotlinObject que intente convertir una cadena JSON en un objeto Kotlin simple con un tipo especificado por el tipo genérico T la función. Podemos usar com.fasterxml.jackson.module.kotlin para 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 método readValue toma un tipo en el que se supone que analiza el JsonObject . Si intentamos obtener la Class del parámetro de tipo T , el compilador se queja: "No se puede usar ''T'' como parámetro de tipo reificado. Utilice una clase en su lugar".

b) Solución alternativa con parámetro de Class explícito

fun <T: Any> String.toKotlinObject(c: KClass<T>): T { val mapper = jacksonObjectMapper() return mapper.readValue(this, c.java) }

Como solución alternativa, la Class de T se puede convertir en un parámetro de método, que luego se usa como argumento para 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) El camino de Kotlin: reified

El uso de una función en inline con el parámetro de tipo reified T 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 la Class de T adicionalmente, T puede usarse como si fuera 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 tipo reified no se puede llamar desde el código Java .

Estoy tratando de comprender el propósito de la palabra clave reified , aparentemente nos permite reflexionar sobre los genéricos .

Sin embargo, cuando lo dejo afuera, funciona igual de bien. ¿Alguien quiere explicar cuándo esto hace una diferencia real?