2013-06-27 54 views
1

我有一個Foo類型的子類型。爲什麼GenSet聲明具有不變類型參數?

我有一個包含,除其他事項外,一個Foo另一個類:

class FooResult(val foo: Foo ... 

我有一組FooResult,我想拉FOOS出它與地圖(),然後計算該組(Foos)和另一組Foos之間的差異。 「結果」下面是將[FooResult]和 - 這是關鍵的部分 - 包是一組[_ <:富]

​​

第二行不會編譯。當bundle是Set [Foo]而不是Set [_ <:Foo]時,它工作得很好 - 引入了協變性。這是錯誤:

type mismatch; 
found : Set[Foo] 
required: scala.collection.GenSet[_$1] 
Note: Foo >: _$1, but trait GenSet is invariant in type A. 
You may wish to investigate a wildcard type such as `_ >: _$1`. (SLS 3.2.10) 

我一直無法找到任何簡單的解決方法。原諒我的無知,但爲什麼像GenSet這些'助手'類型被聲明爲不變?

我錯過了什麼(很有可能),或者這是某種程度上Scala奇妙的集合框架的弱點(我認爲不太可能)?

回答

3

這是一個有意識的設計決策,使Set.contains/apply typesafe。你不應該有一個s:Set [Int],並且意外地做了一些像s.contains(「x」)這樣的事情,它總是假的,所以可能不是你想要的。此外,Set [T]實現Function [T,Boolean],這隻有在apply方法不採用Any時纔可能。

在scala用戶郵件列表上有關於這個主題的無窮無盡的討論。例如參見thisthis

這裏是從保羅·菲利普斯從彙總的理由非常好第二次討論報價:

「是的,申請(化名爲包含)設置的中央操作,而 包含確實」只是一些方法「

沒有人說你有時不想要一個協變集,但總的來說,它更有用的是不變的。

請注意,您始終可以通過隱式轉換將協方差添加到集合中。這意味着如果你有例如一個Set [Int]和一個Set [Any]的方法,它會起作用。但是這也意味着您現在可能會意外地調用Set [Int] .contains(「x」),並且編譯器不會捕獲錯誤(您將始終得到錯誤)。

scala> implicit def setIsCovariant[T,U <: T](s:Set[U]):Set[T] = s.asInstanceOf[Set[T]] 
setIsCovariant: [T, U <: T](s: Set[U])Set[T] 

scala> val s : Set[Int] = Set(1,2,3,4) 
s: Set[Int] = Set(1, 2, 3, 4) 

scala> s.contains("x") 
res0: Boolean = false 

scala> val a: Set[Any] = s 
a: Set[Any] = Set(1, 2, 3, 4) 
+0

好的 - 你能或者有人請給我一些做我需要做的事情的例子嗎?是否需要建設新的集合? (即使我想訴諸於此,我也不認爲演員可以做到這一點。)謝謝! –

+0

嗯,我只是用[Foo]而不是[ - <:Foo]的集合來編寫代碼。這似乎是最好的。 –

相關問題