2011-03-18 58 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類的參數類型,它們都是逆變的。