2011-03-18 30 views
28

我在想下面的例子来说明为什么逆变是有用的。逆变的例子

让我们考虑一个带有Widgets,EventsEvent 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]) 

这些方法只接受 “特定” 事件侦听器,这是罚款。不过,我想定义的还有“厨房 - 吸收器”听众,它们监听所有事件,并将这些监听器传递给上面的“添加监听器”方法。

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

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

由于性状EventListener逆变Event我们可以通过LogEventListener所有那些“添加监听器”的方法,而不会失去他们的类型安全。

它有道理吗?

+0

+1好问题,不好的接受率。伤心! – Nishant 2011-03-18 14:04:34

回答

6

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

6

对我也有意义。作为一个经验法则,参数化类型Type[A]应该与其类型参数A相反,每次它意图接受A的实例来通过接受它们作为参数来做某事。

例如,Java类型Comparator[T],如果它在Scala中被定义,就会被逆变:一个Comparator[Any]应该是Comparator[String]一个亚型,因为它可以比较所有对象Comparator[String]可以比较,等等。最普遍的例子是FunctionX类的参数类型,它们都是逆变的。