android 为什么我们可以在Kotlin的列表的协方差类型示例中传递一个逆变

rks48beu  于 2023-01-24  发布在  Android
关注(0)|答案(1)|浏览(119)

我想知道为什么可以在List的协方差类型示例中传递一个逆变
我创建了这个接口,如您所见,I是一个逆变器,但我能够传递到列表

interface ListMapper<in I, out O> : Mapper<List<I>, List<O>>

如果选中,您将看到该列表接受协方差类型

public interface List<out E> : Collection<E> {...}

为什么以及如何能够做到这一点?

qxgroojn

qxgroojn1#

据推测,Mapper接口中的第一个类型在声明位置是逆变的。
你想象中的限制没有理由存在,List的协方差是List功能的内部因素,与Mapper的功能无关。
List是协变的,这意味着它不能使用任何T,所以用一个不使用任何东西的非泛型类来替换它可能会简化你的理解,比如Int,它是不可变的。

interface IntMapper : Mapper<Int, Int>

这和List没有什么不同,你有一个不消耗任何东西的类型,但是它可以作为Mapper的输入。
从评论中回答您的后续问题:
HashMap的K类型在声明位置是不变的,为了简化讨论,我们只使用MutableList,它也有一个不变类型(这样我们就不会被Map的第二个V类型搞糊涂了)。
让我们也简化并使用一个更基本的接口,它只消耗,这样我们就不会被Mapper中的第二种类型所迷惑:

interface Consumer<in I>

所以现在我们有:

// Allowed:
class ListConsumer<in I> : Consumer<List<I>>

// Not allowed:
class MutableListConsumer<in I> : Consumer<MutableList<I>> // Compile error

假设你有一个ListConsumer,因为ListConsumer是逆变的,所以它允许你将ListConsumer<Number>强制转换为更严格的类型ListConsumer<Int>

val numberListConsumer: ListConsumer<Number> = //...
val intListConsumer: ListConsumer<Int> = numberListConsumer

这是有道理的,如果你可以消费List<Number>,那么消费任何List<Int>都是安全的,因为由于List的协变类型,List<Int>也是List<Number>
但是这对MutableList没有意义,MutableList<Int>不是MutableList<Number>,因为MutableList的类型是不变的。

相关问题