7

我目前正在为一个库编写一个 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
    }

因为我收到一个错误:

公共 API 内联函数无法访问非公共 API 'private final val consumer...

到目前为止,我似乎无法在最有用的地方使用具体类型参数。有解决方法吗?

4

2 回答 2

8

公共inline函数不能private直接使用声明,因为当在类外的调用站点内联时,用法将具有不正确的访问级别(在 JVM 上,private不能从外部访问类的成员)。

您可以做的是使用Kotlin中的internal可见性:在 JVM 上,具有此可见性修饰符的成员将被编译为名称混乱的公共成员(因此仍然可见但不容易从 Java 调用),并且 Kotlin 编译器将至少控制 Kotlin 代码的用法。

有几种方法可以internal从 a 中访问成员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
}
于 2017-03-11T23:20:20.833 回答
2

如果您需要具体类型参数来反映其 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 调用该非内联重载。

于 2017-03-12T01:57:12.430 回答