Actualmente estoy escribiendo un DSL para una biblioteca y me gustaría proporcionar metadatos de tipo utilizando parámetros de tipo cosificados como este:
val config = Config.create() .consumerFor<MyType>{ // consume } Mi problema es que solo puedo usar la palabra clave reified en funciones en inline y en una función en inline no puedo usar campos de instancia como este:
inline fun <reified T> consumerFor(consumer: (T) -> Unit) { consumers.put(T::class.java, consumer) return this }porque me sale un error:
La función en línea de la API pública no puede acceder a los consumidores de valores finales privados de la API no pública...
Parece que hasta ahora no puedo usar parámetros de tipo cosificados donde serían más útiles. ¿Hay una solución para esto?
Las funciones públicas inline no pueden utilizar declaraciones private directamente porque, cuando se insertan en los sitios de llamada fuera de la clase, los usos tendrán un nivel de acceso incorrecto (en JVM, no se puede acceder a un miembro private de una clase desde el exterior).
Lo que puede hacer es usar la visibilidad internal en Kotlin: en JVM, los miembros con este modificador de visibilidad se compilarán en miembros públicos con sus nombres alterados (por lo tanto, aún visibles pero no fáciles de llamar desde Java), y el compilador de Kotlin al menos controlará los usos del código Kotlin.
Hay algunas formas de acceder a un miembro internal desde dentro de una public inline fun , consulte esta pregunta: (enlace)
En tu caso particular, preferiría hacerlo con @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 } O, si no le importa exponer a consumers con @PublishedApi , puede hacerlo de la siguiente manera:
@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 }Si todo lo que necesita el parámetro de tipo cosificado es para reflejar su clase Java, entonces puede administrarlo con una sobrecarga no en línea con el parámetro Class<T> adicional.
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) } De esta manera no ha expuesto la propiedad consumers efectivamente publicada. El punto extra es que también puede llamar a esa sobrecarga no en línea desde Java.