如何在 Kotlin 的实例字段中存储具体化的类型数据?

How can I store reified type data in instance fields in Kotlin?

我目前正在为一个库编写 DSL,我想使用像这样的具体化类型参数来提供类型元数据:

    val config = Config.create()
            .consumerFor<MyType>{
              // consume
            }

我的问题是我只能在 inline 函数中使用 reified 关键字,而在 inline 函数中我不能使用这样的实例字段:

    inline fun <reified T> consumerFor(consumer: (T) -> Unit) {
        consumers.put(T::class.java, consumer)
        return this
    }

因为我得到一个错误:

Public-API inline function cannot access non-public-API 'private final val consumers...

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

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

你可以做的是在 Kotlin 中使用 the internal visibility:在 JVM 上,具有此可见性修饰符的成员将被编译为 public 名称被破坏的成员(因此仍然可见但不容易-从 Java 调用),Kotlin 编译器至少会控制 Kotlin 代码中的用法。

有几种方法可以从 public inline fun 中访问 internal 成员,请参阅此问题:

在您的特定情况下,我更愿意使用 @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
}

如果您只需要具体化类型参数来反映其 java class,那么您可以使用带有附加 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.

调用非内联重载