Я намагаюся зрозуміти призначення 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)