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
自己。但是由于我上面的解释,你必须写它是正常的。
我们刚刚看到 featureImpl1
是 SubPresenter<FeaturedTestAdapterContract.View>
。它不能分配给 SubPresenter<FeaturedCardAdapterContract.View>
(没有 out),因为这意味着它需要接受比实际更多的类型。
将接口重命名为 Processor
、Animal
和 Dog
,您将明白为什么编译器对类型的判断是正确的,而您尝试做的却不正确有道理。
这里是重命名:
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>>
并不是你想要的。
在下面的代码中,如果我们在 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
自己。但是由于我上面的解释,你必须写它是正常的。
我们刚刚看到 featureImpl1
是 SubPresenter<FeaturedTestAdapterContract.View>
。它不能分配给 SubPresenter<FeaturedCardAdapterContract.View>
(没有 out),因为这意味着它需要接受比实际更多的类型。
将接口重命名为 Processor
、Animal
和 Dog
,您将明白为什么编译器对类型的判断是正确的,而您尝试做的却不正确有道理。
这里是重命名:
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>>
并不是你想要的。