逆变的例子

时间:2011-03-18 12:21:00

标签: scala contravariance

我正在考虑以下示例来说明为什么逆变是有用的。

让我们考虑一个包含WidgetsEventsEvent Listeners的GUI框架。

abstract class Event;
class KeyEvent extends Event
class MouseEvent extends Event

trait EventListener[-E] { def listen(e:E) }

Widgets定义以下方法:

def addKeyEventListener(listener:EventListener[KeyEvent])
def addMouseEventListener(listener:EventListener[MouseEvent])

这些方法只接受“特定”事件监听器,这很好。但是我想定义“kitchen-sink”监听器,它们监听所有事件,并将这些监听器传递给上面的“添加监听器”方法。

例如,我想定义LogEventListener来记录所有传入的事件

class LogEventListener extends EventListener[Event] {
   def listen(e:Event) { log(event) }
}

由于EventListener中的特征Event逆变,我们可以将LogEventListener传递给所有这些“添加侦听器”方法,而不会失去其类型安全性。

有意义吗?

2 个答案:

答案 0 :(得分:7)

无论如何,这对我来说很有意义。它也是我见过的最直观的例子之一:自然地收听所有事件的东西会听取关键事件或鼠标事件。

答案 1 :(得分:7)

对我也有意义。根据经验,参数化类型Type[A]在其类型参数A 时应该是逆变的,每次它都要接受A的实例来对它们做某事通过接受它们作为参数

例如,Java类型Comparator[T](如果已在Scala中定义)可能是逆变的:Comparator[Any]应该是Comparator[String]的子类型,因为它可以比较所有Comparator[String]可以比较的对象等等。最一般的例子是FunctionX类的参数类型,它们都是逆变的。