我想知道为什么可以在List的协方差类型示例中传递一个逆变我创建了这个接口,如您所见,I是一个逆变器,但我能够传递到列表
I
interface ListMapper<in I, out O> : Mapper<List<I>, List<O>>
如果选中,您将看到该列表接受协方差类型
public interface List<out E> : Collection<E> {...}
为什么以及如何能够做到这一点?
qxgroojn1#
据推测,Mapper接口中的第一个类型在声明位置是逆变的。你想象中的限制没有理由存在,List的协方差是List功能的内部因素,与Mapper的功能无关。List是协变的,这意味着它不能使用任何T,所以用一个不使用任何东西的非泛型类来替换它可能会简化你的理解,比如Int,它是不可变的。
Mapper
T
Int
interface IntMapper : Mapper<Int, Int>
这和List没有什么不同,你有一个不消耗任何东西的类型,但是它可以作为Mapper的输入。从评论中回答您的后续问题:HashMap的K类型在声明位置是不变的,为了简化讨论,我们只使用MutableList,它也有一个不变类型(这样我们就不会被Map的第二个V类型搞糊涂了)。让我们也简化并使用一个更基本的接口,它只消耗,这样我们就不会被Mapper中的第二种类型所迷惑:
List
K
MutableList
V
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>:
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的类型是不变的。
List<Number>
List<Int>
MutableList<Int>
MutableList<Number>
1条答案
按热度按时间qxgroojn1#
据推测,
Mapper
接口中的第一个类型在声明位置是逆变的。你想象中的限制没有理由存在,List的协方差是List功能的内部因素,与Mapper的功能无关。
List是协变的,这意味着它不能使用任何
T
,所以用一个不使用任何东西的非泛型类来替换它可能会简化你的理解,比如Int
,它是不可变的。这和
List
没有什么不同,你有一个不消耗任何东西的类型,但是它可以作为Mapper的输入。从评论中回答您的后续问题:
HashMap的
K
类型在声明位置是不变的,为了简化讨论,我们只使用MutableList
,它也有一个不变类型(这样我们就不会被Map的第二个V
类型搞糊涂了)。让我们也简化并使用一个更基本的接口,它只消耗,这样我们就不会被Mapper中的第二种类型所迷惑:
所以现在我们有:
假设你有一个ListConsumer,因为ListConsumer是逆变的,所以它允许你将
ListConsumer<Number>
强制转换为更严格的类型ListConsumer<Int>
:这是有道理的,如果你可以消费
List<Number>
,那么消费任何List<Int>
都是安全的,因为由于List
的协变类型,List<Int>
也是List<Number>
。但是这对MutableList没有意义,
MutableList<Int>
不是MutableList<Number>
,因为MutableList的类型是不变的。