在Effective Java中,Joshua Bloch讨论了PECS (生产者-扩展,消费者-超级)的原理。
我对此的理解是,为了增加API的灵活性,输入(产生的集合)应该是协变的,而输出(消费的集合)应该是逆变的。
实现此原则的函数可以具有以下签名:
private static void func( ArrayList<? extends Object> input, ArrayList<? super Integer> output)然而,在Scala中,Function1特征有以下签名:
trait Function1[-T1, +R] extends AnyRefT1 (输入类型)是逆变的,而R(输出类型)是协变的。
我的理解正确吗?如果是这样的话,为什么在Scala的Function1特性中没有应用PECS呢?
发布于 2012-07-01 10:35:27
Joshua是正确的,Scala也是正确的。实际上,Scala强制执行此规则,因此您无需担心。Java没有变化注解,只能在调用点凑合使用,所以需要它们来指导程序员进行正确的设计。
Scala在定义位置有变化注释,而java在调用位置有存放点。调用的输出是定义的输入,反之亦然。
Function1不会读取参数,也不会写入结果,而这正是reduce在Joshua的示例中所做的。相反,您必须将Function1视为一个集合。
当您写入集合时,该集合就是使用者。类似于函数:当你调用它的时候,你就是在写它。因此,正在写入的输入参数必须是反向变量。
同样,当您从一个集合中读取时,该集合就是一个生产者。您可以通过查看结果来读取函数,因此输出参数必须是协变的。
如您所见,这正是Function1表示法。
发布于 2012-06-30 18:33:07
func上的通配符适用于传递给该方法的类型。它们意味着可以为输入传递任何ArrayList,并且可以为输出传递ArrayList<Object>、ArrayList<Number>或ArrayList<Integer>。该方法本身不是泛型的。
对于scala Function1类型,差异应用于该类型,因此可以在需要Function1[AnyRef, Integer]的地方使用Function[AnyRef, Number]。
https://stackoverflow.com/questions/11272819
复制相似问题