[英]Scala Set[_] vs Set[Any]
我有以下代碼行:
case set: Set[Any] => setFormat[Any].write(set)
但是,編譯器會發出警告:
非變量類型參數類型模式中的任何類型scala.collection.Set [Any]未被選中,因為它被擦除[warn]
很公平。
所以我改變了我的路線:
case set: Set[_] => setFormat[Any].write(set)
現在我收到一個錯誤:
[錯誤]發現:scala.collection.Set [_]
[error] required:scala.collection.Set [Any]
Q1。 這兩者有什么區別?
然后我將我的代碼更改為以下內容:
case set: Set[_] => setFormat[Any].write(set.map(s => s))
現在很高興沒有任何錯誤或警告。
Q2。 這為什么有用?
Q1 : Set[Any]
是一個元素類型為Any的Set。 Set[_]
是一個元素類型未知的Set。 也許它是Set[Int]
,也許是Set[String]
,也許是Set[Any]
。 與大多數(不可變的)集合相反,Set不是協變的(聲明是trait Set[A]
,而不是trait Set[+A]
)。 所以Set[String]
不是Set[Any]
,更一般地說,你不能保證你不知道的元素類型的集合(即Set[_]
)是Set[Any]
。
Q2 :它起作用,因為無論集合元素的(未知)類型A,標識函數s => s
都可以被認為是函數A => Any。 (方差是Function1[-T1, +R]
。然后,生成的set.map(s => s)
可以根據需要輸入Set[Any]
。
備注 :如果沒有setFormat和write的定義很難確定,但是你真的需要在setFormat[Any]
使用[Any]
類型參數顯式嗎? 人們可以將存在主義傳遞給通用函數,即
val x: X[_] = ....
def f[A](xa: X[A]) = ...
f(x) // allowed
但是不允許在呼叫站點顯式(例如f[Any](x)
),因為我們不知道X
是否是X[Any]
。
注意:關於Set不協變 :這是不幸的,因為人們非常感覺一組Cats也是一組動物。 這是一個原因(可能還有其他原因)。
Set有一個方法def contains(a: A): Boolean
,這個簽名可以防止協方差。 其他集合的def contains[A1 >: A](a: A): Boolean
,它允許協方差,但實際上等效於def contains(a: Any): Boolean
。
它起作用,因為實現基於方法equals
,可用於任何地方(JVM附帶)並且接受Any
類型的參數。 使用與列表內容無關的類型的值進行調用很可能是一個錯誤,並且更受限制的簽名會更好,但是為協方差付出的代價很小。
但是這個寬松的簽名contains
約束,實現基於equals
(也可能是hashCode
)。 它不適用於基於Ordering的實現,它不接受無類型的參數。 禁止這種(非常常見的)集合實現可能被視為協方差的代價太高。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.