
6.5.3 使用逆变
看看copyFromTo()方法,从任何Array<T>中复制对象,其中T是Fruit类型或Fruit的一个派生类,都是有意义的。协变帮助Kotlin相信,灵活使用from参数是安全的。现在让我们将注意力转向to参数。参数的类型为不变的Array<Fruit>。
如果我们将Array<Fruit>传递给to参数,则不会产生任何问题。但是,如果我们希望将一个Fruit或Fruit的一个派生类传递到一个Fruit集合或任何一个Fruit基集合的类中,会怎么样呢?如果我们想要那种灵活性,我们不能简单地将Array<Any>的实例作为参数传递给to参数。我们必须显式地要求编译器允许逆变——也就是说,在需要参数类型实例的地方接受一个基的参数类型。
在不使用逆变的情况下,让我们首先尝试将一个Array<Any>的实例传递给参数to,看Kotlin会说什么:

这是不行的,同样是由于Kotlin的默认类型不变行为保护了我们。我们可以再次要求Kotlin放松,但是这次允许参数类型是参数类型的类型或基类型——逆变。

唯一的变化是对第二个参数,也就是to: Array<Fruit>现在变成了to: Array<in Fruit>。in规范告诉Kotlin允许在该参数上设置值的方法调用,而不允许读取的方法。
现在,让我们重试一下之前试过的调用:

没问题。这也是一个“使用点型变”,但是这次是针对逆变(in)而不是协变(out)。就像协变的“声明点型变”一样,可以用参数类型<in T>定义类,来通用地指定逆变——也就是说,该类型只能接收参数类型,不能返回或传递参数类型。
设计泛型函数和类并不是一件简单的任务,我们必须花时间考虑类型、变化和结果。在使用参数类型时,我们必须考虑的另一件事是约束可以传递的类型。我们下面将看到。