2011-08-23 77 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

恭喜: - )... –