当类型参数在声明站点协变时,强制它在使用站点保持不变

人气:773 发布:2022-10-16 标签: reflection generics covariance generic-variance kotlin

问题描述

我正在KProperty1上构建扩展函数。该函数需要接受扩展属性(R)的值类型的参数,即使KProperty1在类型参数R中是协变的。

下面是一个稍微做作的例子,尽管我的使用更合法。

data class Data(val value: String)

fun <V> KProperty1<*, V>.setMagically(value: V) {
    this.javaField?.set(null, value)
}

fun test() {
    // I would like this to fail to compile
    Data::value.setMagically(190)
}

编译器似乎正在为R推断类型Any,这是完全有效的,因为KProperty1<*, String> : KProperty1<*, Any>

我想说的是,对于我的特定情况,我实际上希望V是不变的。我知道您可以使用outin作为差异加宽器,但我不知道如何指定要在此情况下使用不变性覆盖KProperty1上的协变批注。

值得注意的是,它在KMutableProperty1中工作得很好,因为R中是不变的。但我的代码也需要使用非可变属性。

对于上下文,我正在构建一些生成数据库查询的东西,这就是为什么我需要值是属性类型的子类,尽管我实际上并没有写入属性,但这个问题比我的特定属性处理情况更一般。

推荐答案

这在科特林中目前是不可能的。事实上,有一个内部注释支持这种行为(如果推断出Any,但没有提到它在调用点的任何地方,则会导致编译器报告错误),并在kotlin-stdlib中的多个位置使用它,但仍不鼓励在标准库之外使用它。

我们计划将此注释公之于众。有关更多详细信息,请查看KT-13198。

113