Как я могу хранить данные овеществленного типа в полях экземпляра в Kotlin?
В настоящее время я пишу DSL для библиотеки, и я хотел бы предоставить метаданные типа, используя такие параметры овеществленного типа:
val config = Config.create()
.consumerFor<MyType>{
// consume
}
Моя проблема заключается в том, что я могу использовать только ключевое слово reified
в функциях inline
, а в функции inline
я не могу использовать такие поля экземпляра:
inline fun <reified T> consumerFor(consumer: (T) -> Unit) {
consumers.put(T::class.java, consumer)
return this
}
Потому что я получаю ошибку:
Встроенная функция Public-API не может получить доступ к частным конечным потребителям непубличного API...
Похоже, что пока я не могу использовать овеществленный тип параметры, где они будут наиболее полезны. Есть ли обходной путь для этого?
2 ответа:
Public
inline
функции не могут использовать объявленияprivate
напрямую, потому что, когда они встроены в сайты вызовов вне класса, использование будет иметь неверный уровень доступа (в JVM член классаprivate
не может быть доступен извне).Что вы можете сделать, так это использовать видимость
internal
в Kotlin: на JVM члены с этим модификатором видимости будут скомпилированы в открытые члены с искаженными именами (поэтому все еще видимые, но не легко вызываемые из Java), и компилятор Kotlin будет по крайней мере контролировать использование кода Kotlin.Существует несколько способов доступа к члену
internal
изpublic inline fun
, см. Этот вопрос: (Ссылка)В вашем конкретном случае я предпочел бы сделать это с помощью
@PublishedApi
:private val consumers = mutableMapOf<Class<*>, Any>() @PublishedApi internal fun <T> putConsumer(clazz: Class<out T>, consumer: (T) -> Unit) { consumers.put(clazz, consumer) } inline fun <reified T> consumerFor(noinline consumer: (T) -> Unit): C { putConsumer(T::class.java, consumer) return this }
Или, если вы не против разоблачить
consumers
с@PublishedApi
, то вы можете сделать это следующим образом:@PublishedApi internal val consumers = mutableMapOf<Class<*>, Any>() inline fun <reified T> consumerFor(noinline consumer: (T) -> Unit): C { consumers.put(T::class.java, consumer) return this }
Если все, что вам нужно, чтобы параметр reified type отражал его класс java, то вы можете управлять нестрочной перегрузкой с дополнительным параметром
Class<T>
.inline fun <reified T> consumerFor(noinline consumer: (T) -> Unit) = consumerFor(T::class.java, consumer) fun <T> consumerFor(key: Class<T>, consumer: (T) -> Unit) = apply { consumers.put(key, consumer) }
Таким образом, вы не выставляете
consumers
свойство эффективно опубликованным. Суть бонуса заключается в том, что можно назвать не-встроенный перегрузки и от Java.