【问题标题】:How can I store reified type data in instance fields in Kotlin?如何在 Kotlin 的实例字段中存储具体类型数据?
【发布时间】:2017-08-02 04:01:36
【问题描述】:

我目前正在为一个库编写 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 内联函数无法访问 non-public-API 'private final val consumer...

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

【问题讨论】:

    标签: java kotlin reification


    【解决方案1】:

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

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

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

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

    【讨论】:

    • 这样就好了,谢谢。这只是一个带有最终字段的配置类,所以我不介意。
    【解决方案2】:

    如果您需要具体化类型参数来反映其 java 类,那么您可以通过附加 Class&lt;T&gt; 参数来管理非内联重载。

    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 调用该非内联重载。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-06-12
      • 2016-07-15
      • 1970-01-01
      • 2017-11-11
      • 1970-01-01
      • 2021-07-14
      • 2023-03-19
      • 2021-12-17
      相关资源
      最近更新 更多