为什么泛型型变修饰符会影响Kotlin中flatMapTo函数的正常运行?
Kotlin 泛型形变修饰符
in/out替换报错问题解答 核心原因:泛型形变的读写限制
首先要明确Kotlin声明处形变的作用:
out R(协变):代表当前泛型类是生产R类型实例的,只允许对外返回R类型值(读操作),禁止接收R类型作为入参(写操作),否则会有类型安全风险。in R(逆变):代表当前泛型类是消费R类型实例的,允许接收R类型作为入参(写操作),对外返回值只能是Any类型。
你提到的MutableCollection<E>的addAll方法签名为:
fun addAll(elements: Collection<E>): Boolean
该方法的作用是将elements集合内的每一个元素逐个添加到当前集合,而非将整个elements集合作为单个元素添加,这是你理解偏差的核心点。
原代码正常运行的逻辑
原声明C : MutableCollection<in R>中,in R明确集合是用来消费R类型的,支持写入R及其子类型的元素:
transform返回值是Iterable<R>,内部存储的元素类型为R- 调用
destination.addAll(list)时,传入的list内元素都是R类型,完全符合addAll的入参要求,因此可以正常运行。
替换为out后报错的逻辑
当你把声明改为C : MutableCollection<out R>后:
out R表示该集合是生产R类型的,仅支持读取操作,所有接收E类型作为入参的写方法(包括add、addAll等)都会被类型系统限制- 此时
addAll要求的入参Collection<E>的E类型被限制为Nothing(Kotlin中所有类型的子类型,不存在可实例化的对象),你传入的Iterable<R>自然不符合要求,就会抛出“预期参数类型为Nothing”的错误。
结合你的示例验证
你给出的示例:
val list = listOf("abc") list.flatMap{it.toList()}
这个场景下:
- 泛型参数
T为String,transform函数返回值是Iterable<Char>,因此R的实际类型是Char flatMap内部调用addAll时,是把it.toList()返回的List<Char>里的每个Char元素添加到目标集合,而非把整个List<Char>作为元素添加- 如果目标集合声明为
MutableCollection<out Char>,写操作被禁止,自然无法执行添加逻辑。
内容的提问来源于stack exchange,提问作者ntos
相关产品推荐
相关产品推荐

