Что делает ключевое слово reified в Kotlin?

Я пытаюсь понять цель ключевого слова reified, видимо, это позволяет нам размышлять над дженериками .

Однако, когда я оставляю это, он работает так же хорошо. Кто-нибудь должен объяснить, когда это имеет реальное значение?

Solutions Collecting From Web of "Что делает ключевое слово reified в Kotlin?"

Зачем нам это нужно

В обычной общей функции fun <T> myGenericFun(c:Class<T>) вы не можете получить доступ к типу T потому что он доступен только во время компиляции, но стирается во время выполнения. Поэтому, если вы хотите использовать общий тип как обычный класс в теле функции, вам нужно явно передать класс как параметр, как в моем примере.

Однако, если вы выполняете inline функцию с помощью reified T , тип T можно получить даже во время выполнения, и вам не нужно дополнительно передавать Class<T> . Вы можете работать с T как если бы это был обычный класс, например, вы можете проверить, является ли переменная экземпляром T , который вы можете легко сделать: myVar is T

Такая функция выглядит следующим образом:

 inline fun <reified T> myGenericFun() 

Как это работает под капотом

Вы можете использовать только reified в сочетании с inline функцией. Такая функция заставляет компилятор копировать байт-код функции в любое место, где используется функция (функция «встроена»). Когда вы вызываете встроенную функцию с типом reified, компилятор знает фактический тип, используемый как аргумент типа, и модифицирует сгенерированный байт-код для непосредственного использования соответствующего класса. Поэтому вызовы типа 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(JsonObject(this).encode(), T::class.java) } 

Метод readValue хочет, чтобы мы сказали, какой тип он должен анализировать JsonObject . Мы пытаемся использовать параметр типа T и получить его Class .

Это не работает, и компилятор говорит нам: «Невозможно использовать« T »в качестве параметра типа reified. Вместо этого используйте класс».

Рабочий пример без подтверждения

 fun <T> String.toKotlinObject(c: Class<T>): T { val mapper = jacksonObjectMapper() return mapper.readValue(JsonObject(this).encode(), c) } 

Следующим шагом было бы передать класс T явно, который может быть непосредственно использован в качестве аргумента readValue . Это работает, и это то, что мы сделали на Java. Его можно назвать так:

 "{}".toKotlinObject(MyJsonType::class.java) 

С овеществлением

Использование inline функции с параметром типа reified T позволяет реализовать нашу функцию следующим образом:

 inline fun <reified T> String.toKotlinObject(): T { val mapper = jacksonObjectMapper() return mapper.readValue(JsonObject(this).encode(), T::class.java) } 

Не нужно дополнительно передавать Class T , T можно использовать, как если бы это был обычный класс. Для клиента код выглядит следующим образом:

 "{}".toKotlinObject<MyJsonType>() 

Важный

Встроенная функция с типами reified не может быть вызвана из кода Java .