Kotlin 通用自动转换为 "out"

Kotlin Generic auto conversion to "out"

在下面的代码中,如果我们在 base 中使用泛型,然后在 diff 接口中扩展它,kotlin 不尊重 base 接口的泛型。

为什么会这样?

在基础中我没有使用“in”或“out”,但默认情况下扩展接口仍然是“out”。

interface FeaturedCardAdapterContract {
interface View {
    fun onCreate()
  }

interface SubPresenter<V : View> {
    fun onBind(v: V)
  }
}

interface FeaturedTestAdapterContract {
   interface View : FeaturedCardAdapterContract.View
   interface Presenter : FeaturedCardAdapterContract.SubPresenter<View>
}

fun main() {
val featureImpl1: FeaturedTestAdapterContract.Presenter = object : FeaturedTestAdapterContract.Presenter {
    override fun onBind(v: FeaturedTestAdapterContract.View) {
    }
}
val featureImpl2: FeaturedTestAdapterContract.Presenter = object : FeaturedTestAdapterContract.Presenter {
    override fun onBind(v: FeaturedTestAdapterContract.View) {
    }
}

//Works but i won't be able to consume it in onBind bcz kotlin assumed it as "out"
val interfaceArray: Array<FeaturedCardAdapterContract.SubPresenter<out FeaturedCardAdapterContract.View>> = arrayOf(featureImpl1, featureImpl2)

//Dosen't Work-bcz kotlin assumes the type of featureImpl1 is FeaturedCardAdapterContract.SubPresenter<out FeaturedCardAdapterContract.View> ,Why?
val interfaceArray: Array<FeaturedCardAdapterContract.SubPresenter<FeaturedCardAdapterContract.View>> = arrayOf(featureImpl1, featureImpl2)

//Works but,Same as 1st method
val interfaceArray: Array<FeaturedCardAdapterContract.SubPresenter<*>> = arrayOf(featureImpl1, featureImpl2)

for (featureImpl in interfaceArray) {
    //Won't work bcz of "out"
    featureImpl.onBind(object : FeaturedCardAdapterContract.View {
        override fun onCreate() {
            //
        }
    })
}
}

澄清一下,您已将 featureImpl1 定义为 FeaturedTestAdapterContract.Presenter,因此它是 FeaturedCardAdapterContract.SubPresenter<FeaturedTestAdapterContract.View>

注意这里是“测试”视图,而不是“卡片”视图。这是您自己对 Presenter 的定义 - 您在定义中使用的 View 是测试视图 FeaturedTestAdapterContract.View 的快捷方式,而不是卡片 FeaturedCardAdapterContract.View:

val featureImpl1: FeaturedTestAdapterContract.Presenter = object : FeaturedTestAdapterContract.Presenter {
    // only wants test views here
    override fun onBind(v: FeaturedTestAdapterContract.View) {
}

现在检查这部分:

Won't work bcz of "out"

featureImpl.onBind(object : FeaturedCardAdapterContract.View {
    //...
})

让我们暂时忘记 out。您已经定义了 featureImpl1,因此它接受将 绑定到特定的 FeaturedTestAdapterContract.View。但在这里您试图传递卡片视图 FeaturedCardAdapterContract.View,这不是测试视图。如果允许这样做,featureImpl1 的主体就会失败,因为它被赋予的对象不是 FeaturedTestAdapterContract.View 类型,甚至不是它的子类型。

//Works but i won't be able to consume it in onBind bcz kotlin assumed it as "out"
val interfaceArray: Array<FeaturedCardAdapterContract.SubPresenter<out FeaturedCardAdapterContract.View>> = arrayOf(featureImpl1, featureImpl2)

Kotlin 在这里没有假设任何东西,您正在标记 out 自己。但是由于我上面的解释,你必须写它是正常的。

我们刚刚看到 featureImpl1SubPresenter<FeaturedTestAdapterContract.View>。它不能分配给 SubPresenter<FeaturedCardAdapterContract.View>(没有 out),因为这意味着它需要接受比实际更多的类型。

将接口重命名为 ProcessorAnimalDog,您将明白为什么编译器对类型的判断是正确的,而您尝试做的却不正确有道理。

这里是重命名:

interface Animal // FeaturedCardAdapterContract.View

interface Processor<A: Animal> { // FeaturedCardAdapterContract.SubPresenter<V>
    fun process(animal: A) // onBind
}

interface Dog: Animal // FeaturedTestAdapterContract.View
interface DogProcessor: Processor<Dog> // FeaturedTestAdapterContract.Presenter

main 中,您正在创建一个包含 2 DogProcessor 的数组:

val processorImpl1 = object: DogProcessor {
    override fun process(animal: Dog) {

    }
}

val processorImpl2 = object: DogProcessor {
    override fun process(animal: Dog) {

    }
}

val array = arrayOf(processorImpl1, processorImpl2)

然后你试图遍历它并让它们每个处理一个动物:

val array = arrayOf(processorImpl1, processorImpl2)
for (processor in array) {
    processor.process(object: Animal {

    })
}

无论您如何更改 array 的类型,这显然都行不通。阵列中的处理器专门处理 ,而不是一般的动物。你可以简单地通过给它狗而不是动物来完成这项工作,或者在你的情况下:

val interfaceArray = arrayOf(featureImpl1, featureImpl2)

for (featureImpl in interfaceArray) {
    featureImpl.onBind(object : FeaturedTestAdapterContract.View {
        override fun onCreate() {
            //
        }
    })
}

请注意,数组的类型可以更改为 Array<Processor<out Animal>> - 仅生产 动物的处理器数组。这是因为狗的生产者是动物的一种生产者。另见:PECS。但是,由于您想在此处调用 process (onBind),因此您希望处理器 吸收 或消耗一种动物,而不是生产一种动物。所以,Array<Processor<out Animal>>并不是你想要的。