2010-09-07 40 views
1

時,我有以下類/性狀斯卡拉缺少編譯/運行時錯誤內嵌

trait Write[-T] { 
    def add(elem : T); 
} 

class ContraListWrapper[T] (var list : List[T]) extends Write[T] { 
    def add(elem : T) = { 
    list = elem :: list 
    } 
} 

def bar(list : Write[Number]) = {} 

調用方法與對象或數字作品的名單,感謝給寫性狀逆變列表。

var list : List[Number] = Nil; 
var wlist = new ContraListWrapper(list); 
bar(wlist); 

var list : List[Object] = Nil; 
var wlist = new ContraListWrapper(list); 
bar(wlist); 

當我用Integer列表調用bar時,我在Scala中收到編譯錯誤。這是預期的;整數號碼(但亞型)的超類型

var list : List[Integer ] = new Integer(1) :: Nil; 
var wlist = new ContraListWrapper(list); 
bar(wlist); //error: type mismatch; 
//found : contra.this.ContraListWrapper[Integer] 
//required: contra.this.Write[Number] 

但是,當我內聯整數列表的一個變量聲明,編譯錯誤不見了,它甚至似乎工作。答案THX雷克斯克爾大膽

1)它是如何可能:

var list : List[Integer] = new Integer(1) :: Nil; 
bar(new ContraListWrapper(list)); //no compile- nor runtime error 

編輯(我可以在方法酒吧元素添加到列表中)? 第一種整數被選中,內聯號碼

2)爲什麼不是沒有內聯的情況? 斯卡拉可以採取適當的類型

3)爲什麼我不會事件獲取運行時錯誤? 因爲列表是協變的

Ps。我知道我可以在沒有特質和包裝的情況下獲得相反的效果,並且有一定的限制。

回答

3

List是協變的,因此List[Number]是超類型List[Integer]。在第二種情況下,Scala查看代碼,然後執行:「呵呵,酒吧想要用Number輸入一些東西,所以讓我們看看我們是否可以讓ContraListWrapper返回。確定我們可以 - 我們可以告訴它它獲得了List[Number]而不是一個List[Integer]「。

在第一種情況下,類型已經固定。

您可以通過更改第二種情況證明這一點爲自己

bar(new ContraListWrapper[Integer](list)); 

這給出了一個編譯時錯誤,因爲它應該,因爲編譯器是不能自由選擇的類型爲Number