逆变的例子

Mic*_*ael 29 scala contravariance

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

让我们考虑一个GUI框架Widgets,EventsEvent Listeners.

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

trait EventListener[-E] { def listen(e:E) }
Run Code Online (Sandbox Code Playgroud)

我们Widgets定义以下方法:

def addKeyEventListener(listener:EventListener[KeyEvent])
def addMouseEventListener(listener:EventListener[MouseEvent])
Run Code Online (Sandbox Code Playgroud)

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

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

class LogEventListener extends EventListener[Event] {
   def listen(e:Event) { log(event) }
}
Run Code Online (Sandbox Code Playgroud)

由于特征EventListener逆变的,Event我们可以传递LogEventListener给所有那些"添加监听器"方法而不会失去其类型安全性.

是否有意义 ?

Dan*_*ral 7

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


Jea*_*let 7

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

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