簡體   English   中英

Scala Set [_] vs Set [Any]

[英]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。 這為什么有用?

Q1Set[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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM