2013-08-02 87 views
5

爲什麼不能編譯這個函數?相交斯卡拉集與子集

case class MyType(n: Int) 
def intersection(s1: Set[MyType], s2: Set[_ <: MyType]) = 
    (s1 & s2) 

我得到以下錯誤:

error: type mismatch; found : Set[_$1] where type _$1 <: MyType required: scala.collection.GenSet[MyType] Note: _$1 <: MyType, but trait GenSet is invariant in type A. You may wish to investigate a wildcard type such as _ <: MyType . (SLS 3.2.10) (w & r)

有沒有一種簡單的方法來「提升」,而無需使用asInstanceOf輸入設置[MyType的]第二個參數?

回答

2

A Set對於其類型參數不是協變的。

因此,一個簡單的解決方法是將轉換爲List(這是協變):

def intersection(s1: Set[MyType], s2: Set[_ <: MyType]) = 
    s1.toList.intersect(s2.toList).toSet 
3

這是因爲Set定義爲Set[A]。它是in-variant而不是co-variant。

&被定義爲

def &(that: GenSet[A]): Set[A] 

它期望和Set[A]類型的參數。但你是提供Set[_ <: MyType]

Set[_ <: Mytype]Set[MyType]的共變體。但正如聲明所說,論證應該是不同的,即Set[MyType],因此是錯誤。

PS:您可以將協方差看作從窄到寬轉換的類型。例如:如果Dog延伸Animal,並且如果你做Animal a = new Dog(),你有一隻狗(狹窄)轉換爲動物(更廣泛)。它上面預計不變的類型。即如果它期望Animal,則只能提供Animal。另一個例子是java.util.ArrayList,它是不同的。

+1

感謝您的解釋。然而,現在我不知道爲什麼這個聲明類型正確:Set(new Object())&Set(「string」) – tba

+0

@tba這是一個非常好的觀察。我在這裏問它:http://stackoverflow.com/questions/18029746/weird-behavior-of-function-in-set。謝謝 – Jatin

2

Set是不變的,但是有一個非常簡單的解決方法:

def intersection(s1: Set[MyType], s2: Set[_ <: MyType]) = 
    s2 filter s1 

或者,如果一個人想以獲得更好的結果類型的類型推斷:

def intersection[X <: MyType](s1: Set[MyType], s2: Set[X]): Set[X] = 
    s2 filter s1 

這裏使用s1作爲函數。函數在參數中是反對變體,因此(MyType) => Boolean類型的s1.apply可接受爲(_ <: MyType) => Boolean

性能與intersect相同,因爲this filter thatintersect是如何實現的Set