#kotlin
#kotlin
Вопрос:
В kotlin вы можете использовать оператор ссылки для получения KProperty свойства расширения пакета следующим образом:
val String.extProp: String
get() = "Some get code"
fun foo() {
val prop: KProperty<String> = String::extProp
}
Однако, когда свойство расширения объявляется внутри класса, оператор ссылки больше не работает:
class Example() {
val String.extProp: String
get() = "Some get code"
fun foo() {
val prop: KProperty<String> = String::extProp // error
}
}
Итак, мне интересно, как я могу изменить проблемную строку во втором примере, чтобы получить свойство KProperty?
Ответ №1:
Ошибка, которую вы получаете, это:
Ошибка: (y, x) Kotlin: ‘extProp’ является членом и расширением одновременно. Ссылки на такие элементы не допускаются
Не существует синтаксического механизма для генерации ссылки на метод расширения, который также требует содержащего класса. Например, ваше расширение может использовать члены класса, и для этого потребуется что-то вроде «связанных ссылок«, входящих в Kotlin 1.1 (что, я не уверен, также будет охватывать этот случай, в настоящее время это открытый вопрос). Итак, на данный момент синтаксис недоступен ::
. Такие вещи, как Example::String::extProp
недоступны, также не является часто используемым Example::String.extProp
синтаксисом. Но вы можете найти его путем отражения.
Сначала вам нужно знать, какой тип вы получите, это:
KProperty2<INSTANCE, EXTENDING, PROPTYPE>
В то время как обычное свойство класса:
KProperty1<INSTANCE, PROPTYPE>
Вам нужно знать это, поскольку для любого вызова getter
потребуется экземпляр класса и экземпляр класса, который расширяет свойство. Таким образом, вы не можете вызывать его так же, как ссылку на свойство класса.
Вы можете использовать эту функцию для поиска свойства расширения, объявленного в классе:
@Suppress("UNCHECKED_CAST")
fun <T: Any, EXTENDING: Any, R: Any> KClass<T>.extProp(extends: KClass<EXTENDING>, name: String, returning: KClass<R>): KProperty2<T, EXTENDING, R> {
return this.declaredMemberExtensionProperties.first {
it.name == name amp;amp;
it.parameters.size == 2 amp;amp;
it.parameters[0].kind == KParameter.Kind.INSTANCE amp;amp; it.parameters[0].type == this.defaultType amp;amp;
it.parameters[1].kind == KParameter.Kind.EXTENSION_RECEIVER amp;amp; it.parameters[1].type == extends.defaultType amp;amp;
it.returnType == returning.defaultType
} as KProperty2<T, EXTENDING, R>
}
Это немного излишне для проверки, но гарантирует, что оно будет надежным в будущем на случай, если позже будут добавлены какие-либо другие типы расширений. Ниже приведен ваш код, обновленный для его использования:
class Example() {
val String.extProp: String
get() = "howdy $this"
fun foo() {
val prop = Example::class.extProp(String::class, "extProp", String::class)
println(prop.get(this, "stringy")) // "howdy stringy"
}
}