Estou tentando entender o objetivo da reified
palavra - chave, aparentemente está nos permitindo refletir sobre os genéricos .
No entanto, quando deixo de fora, funciona tão bem. Alguém quer explicar quando isso faz uma diferença real ?
Estou tentando entender o objetivo da reified
palavra - chave, aparentemente está nos permitindo refletir sobre os genéricos .
No entanto, quando deixo de fora, funciona tão bem. Alguém quer explicar quando isso faz uma diferença real ?
Respostas:
reified
bom parafun <T> myGenericFun(c: Class<T>)
No corpo de uma função genérica como myGenericFun
, você não pode acessar o tipo T
porque ele está disponível apenas em tempo de compilação, mas apagado em tempo de execução. Portanto, se você quiser usar o tipo genérico como uma classe normal no corpo da função que você precisa para passar explicitamente a classe como um parâmetro , como mostrado na myGenericFun
.
Se você criar uma inline
função com um reificada T
no entanto, o tipo de T
pode ser acessado mesmo em tempo de execução e, portanto, você não precisa passar o Class<T>
adicionalmente. Você pode trabalhar com T
como se fosse uma classe normal, por exemplo, você pode querer verificar se uma variável é uma instância T
, que você pode facilmente fazer em seguida: myVar is T
.
Essa inline
função com o reified
tipo T
tem a seguinte aparência:
inline fun <reified T> myGenericFun()
reified
funcionaVocê só pode usar reified
em combinação com uma inline
função . Essa função faz com que o compilador copie o bytecode da função para todos os locais em que a função está sendo usada (a função está sendo "embutida"). Quando você chama uma função embutida com o tipo reificado, o compilador conhece o tipo real usado como argumento de tipo e modifica o bytecode gerado para usar diretamente a classe correspondente. Portanto, chamadas como myVar is T
torne- myVar is String
se (se o argumento de tipo fosse String
) no bytecode e no tempo de execução.
Vamos dar uma olhada em um exemplo que mostra o quão útil reified
pode ser. Queremos criar uma função de extensão String
chamada chamada toKotlinObject
que tenta converter uma string JSON em um objeto Kotlin simples com um tipo especificado pelo tipo genérico da função T
. Podemos usar com.fasterxml.jackson.module.kotlin
isso e a primeira abordagem é a seguinte:
a) Primeira abordagem sem tipo reificado
fun <T> String.toKotlinObject(): T {
val mapper = jacksonObjectMapper()
//does not compile!
return mapper.readValue(this, T::class.java)
}
O readValue
método usa um tipo para o qual ele deve analisar o JsonObject
. Se tentarmos obter o Class
parâmetro type T
, o compilador reclama: "Não é possível usar 'T' como parâmetro do tipo reificado. Use uma classe."
b) Solução alternativa com Class
parâmetro explícito
fun <T: Any> String.toKotlinObject(c: KClass<T>): T {
val mapper = jacksonObjectMapper()
return mapper.readValue(this, c.java)
}
Como solução alternativa, o Class
de T
pode ser um parâmetro de método, que é usado como argumento para readValue
. Isso funciona e é um padrão comum no código Java genérico. Pode ser chamado da seguinte maneira:
data class MyJsonType(val name: String)
val json = """{"name":"example"}"""
json.toKotlinObject(MyJsonType::class)
c) O caminho Kotlin: reified
O uso de uma inline
função com o reified
parâmetro type T
permite implementar a função de maneira diferente:
inline fun <reified T: Any> String.toKotlinObject(): T {
val mapper = jacksonObjectMapper()
return mapper.readValue(this, T::class.java)
}
Não há necessidade de levar o Class
de T
, adicionalmente, T
pode ser usado como se fosse uma classe comum. Para o cliente, o código fica assim:
json.toKotlinObject<MyJsonType>()
Uma função embutida com o reified
tipo não pode ser chamada do código Java .
SIMPLES
* reified é dar permissão para usar no momento da compilação (para acessar T dentro da função)
por exemplo:
inline fun <reified T:Any> String.convertToObject(): T{
val gson = Gson()
return gson.fromJson(this,T::class.java)
}
usando como:
val jsonStringResponse = "{"name":"bruno" , "age":"14" , "world":"mars"}"
val userObject = jsonStringResponse.convertToObject<User>()
println(user.name)