我正在考虑以下示例来说明为什么逆变是有用的。
让我们考虑一个包含Widgets
,Events
和Event 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
传递给所有这些“添加侦听器”方法,而不会失去其类型安全性。
有意义吗?
答案 0 :(得分:7)
无论如何,这对我来说很有意义。它也是我见过的最直观的例子之一:自然地收听所有事件的东西会听取关键事件或鼠标事件。
答案 1 :(得分:7)
对我也有意义。根据经验,参数化类型Type[A]
在其类型参数A
时应该是逆变的,每次它都要接受A
的实例来对它们做某事通过接受它们作为参数。
例如,Java类型Comparator[T]
(如果已在Scala中定义)可能是逆变的:Comparator[Any]
应该是Comparator[String]
的子类型,因为它可以比较所有Comparator[String]
可以比较的对象等等。最一般的例子是FunctionX
类的参数类型,它们都是逆变的。