Я намагаюся зрозуміти призначення reified
ключового слова, мабуть, це дозволяє нам задуматися про генеричні дані .
Однак, коли я залишаю його, це працює так само добре. Будь-догляд пояснити , коли це робить фактичну різницю ?
Я намагаюся зрозуміти призначення reified
ключового слова, мабуть, це дозволяє нам задуматися про генеричні дані .
Однак, коли я залишаю його, це працює так само добре. Будь-догляд пояснити , коли це робить фактичну різницю ?
Відповіді:
reified
добреfun <T> myGenericFun(c: Class<T>)
У тілі такої загальної функції, як myGenericFun
ви, ви не можете отримати доступ до типу, T
оскільки він доступний лише під час компіляції, але стирається під час виконання. Тому, якщо ви хочете використовувати загальний тип як нормальний клас у тілі функції, вам потрібно явно передати клас як параметр, як показано на рисунку myGenericFun
.
Якщо ви створюєте inline
функцію із вдосконаленою T
формою, до цього типу T
можна отримати доступ навіть під час виконання, і тому вам не потрібно додатково передавати Class<T>
. Ви можете працювати з T
як якби це був звичайний клас, наприклад , ви можете захотіти , щоб перевірити , є чи змінна є екземпляром T
, який ви можете легко зробити , то: myVar is T
.
Така inline
функція з reified
типом T
виглядає так:
inline fun <reified T> myGenericFun()
reified
працюєМожна використовувати лише reified
в поєднанні з inline
функцією . Така функція змушує компілятор скопіювати байт-код функції в будь-яке місце, де функція використовується (функція "вбудована"). Коли ви викликаєте вбудовану функцію з рефікованим типом, компілятор знає фактичний тип, що використовується як аргумент типу, і змінює створений байтовий код, щоб безпосередньо використовувати відповідний клас. Тому виклики на зразок myVar is T
стають myVar is String
(якщо аргумент типу String
) були в байт-коді та під час виконання.
Давайте подивимось на приклад, який показує, наскільки корисними reified
можуть бути. Ми хочемо створити функцію розширення для String
виклику, toKotlinObject
який намагається перетворити рядок JSON в звичайний об'єкт Kotlin з типом, визначеним загальним типом функції T
. Ми можемо використовувати com.fasterxml.jackson.module.kotlin
для цього, і перший підхід полягає в наступному:
а) Перший підхід без рефікованого типу
fun <T> String.toKotlinObject(): T {
val mapper = jacksonObjectMapper()
//does not compile!
return mapper.readValue(this, T::class.java)
}
readValue
Метод приймає тип , який він , як передбачається розібрати JsonObject
к. Якщо ми спробуємо отримати Class
параметр типу T
, компілятор скаржиться: "Неможливо використовувати" T "як параметр рефікованого типу. Замість цього використовуйте клас."
б) Обхід із явним Class
параметром
fun <T: Any> String.toKotlinObject(c: KClass<T>): T {
val mapper = jacksonObjectMapper()
return mapper.readValue(this, c.java)
}
Щоб обійти цю проблему, то Class
з T
може бути зроблений параметр методу, який потім використовується в якості аргументу readValue
. Це працює і є загальною схемою в загальному Java-коді. Його можна назвати так:
data class MyJsonType(val name: String)
val json = """{"name":"example"}"""
json.toKotlinObject(MyJsonType::class)
c) Котлінський шлях: reified
Використання inline
функції з reified
параметром типу T
дозволяє реалізувати функцію по-різному:
inline fun <reified T: Any> String.toKotlinObject(): T {
val mapper = jacksonObjectMapper()
return mapper.readValue(this, T::class.java)
}
Там немає необхідності брати Class
з T
додатково, T
може бути використаний , як якщо б це був звичайний клас. Для клієнта код виглядає так:
json.toKotlinObject<MyJsonType>()
Вбудована функція з reified
типом не можна викликати з коду Java .
ПРОСТО
* reified - це надання дозволу на використання під час компіляції (для доступу до T всередині функції)
наприклад:
inline fun <reified T:Any> String.convertToObject(): T{
val gson = Gson()
return gson.fromJson(this,T::class.java)
}
використовуючи:
val jsonStringResponse = "{"name":"bruno" , "age":"14" , "world":"mars"}"
val userObject = jsonStringResponse.convertToObject<User>()
println(user.name)