2011-08-23 76 views
6

我收到「error:type arguments [Any]不符合特性Cloneable的類型參數邊界[+ A <:AnyRef]」的錯誤消息,我可以不要讓頭或尾巴。在for循環和條件語句中添加到scala映射

具體地說,

var M = mutable.Map[Int, mutable.Set[Int]]() 
for(i <- 1 to 100; j <- 1 to 100) { 
    if(!M.contains(i)) {M += i -> mutable.Set[Int](j)} 
    else {M(i) += j} 
} 

(實際上,我試圖更復雜的東西,但是這是調整和簡化爲最小誤差生成代碼)

和上面的代碼的最後一行生成錯誤消息。如果我進一步剝離它

for(i <- 1 to 100; j <- 1 to 100) { 
    if(!M.contains(i)) {M += i -> mutable.Set[Int](j)} 
} 

它的工作原理!

如何使上述代碼有效?

+1

作爲邊注,'M + = I - >(M.getOrElse(I,mutable.Set [INT]())+ j)的'將是一個稍微更習慣寫出循環體的方式。 –

+0

@Travis謝謝!這是我一直在尋找的解決方案。如果您將您的評論轉換爲答案,我很樂意選擇它。 – JasonMond

+0

謝謝,但我認爲下面的答案可能會更好地解決提出的問題? –

回答

6

我甚至進一步降低你的例子:

scala> if(!M.contains(1)) {M += 1 -> mutable.Set[Int](1)} else {M(1) += 1}; 
<console>:9: error: type arguments [Any] do not conform to trait Cloneable's type parameter bounds [+A <: AnyRef] 
val res17 = 
    ^

的問題時好像編譯器試圖尋找共同的返回類型爲兩個分支發生: 第一個是

scala> M += 1 -> mutable.Set[Int](1) 
res19: scala.collection.mutable.Map[Int,scala.collection.mutable.Set[Int]] = ... 

而且「其他」部分是

scala> M(1) += 1 
res18: scala.collection.mutable.Set[Int] = Set(1) 

如果我添加一個返回值到結尾o f此表達式,REPL無誤地吃它:

scala> if(!M.contains(1)) {M += 1 -> mutable.Set[Int](1)} else {M(1) += 1}; println("hello") 
hello 

因爲表達式的返回類型是單位。

+0

謝謝!我現在明白了錯誤信息。但是解決方法太笨拙了。我敢肯定,有一種更加和藹可親的方式來做到這一點。 – JasonMond

7

Digal診斷出這個問題(未能統一if-else分支的類型),它看起來像一個編譯器錯誤。這裏有一個進一步簡化的情況下,這將使在REPL一個錯誤,一個很長的編譯時間後,

if (true) { 
    null: collection.mutable.Map[Int, Int] 
} else { 
    null: collection.mutable.Set[Int] 
} 

在此期間,你可以得到你的代碼中的if-else語句的地方灑顯式類型編譯,

for(i <- 1 to 100; j <- 1 to 100) { 
    if(!M.contains(i)) {M += i -> mutable.Set[Int](j)} 
    else {M(i) += j}: Unit 
} 

我日提交這裏的一個問題:https://issues.scala-lang.org/browse/SI-4938

+1

哇!我以前從來沒有成爲編譯器中的真正bug的發現者。 – JasonMond

+1

恭喜: - )... –