为什么我必须明确声明Tuple2(a,b)才能在foldLeft中使用Map add?

时间:2011-05-09 18:20:10

标签: scala tuples scala-collections

我希望创建一个按名称键入的Map,其中包含具有该名称的事物的数量。我有一个名称的东西列表,其中可能包含多个具有相同名称的项目。像这样编码我得到一个错误“类型不匹配;找到:字符串必需:(String,Int)”:

//variation 0, produces error 
(Map[String, Int]() /: entries)((r, c) => { r + (c.name, if (r.contains(c.name)) (c.name) + 1 else 1) })

这让我感到困惑,因为我虽然(a,b)是Tuple2,因此适合与Map add一起使用。以下任一变体均按预期工作:

//variation 1, works
(Map[String, Int]() /: entries)((r, c) => { r + Tuple2(c.name, if (r.contains(c.name)) (c.name) + 1 else 1) })
//variation 2, works
(Map[String, Int]() /: entries)((r, c) => { 
    val e = (c.name, if (r.contains(c.name)) (c.name) + 1 else 1) })
    r + e

我不清楚我的第一个版本出现问题的原因;任何人都可以建议。我使用Scala-IDE 2.0.0 beta 2编辑源代码;错误来自Eclipse Problems窗口。

3 个答案:

答案 0 :(得分:3)

将单个元组参数传递给与运算符表示法一起使用的方法(如+方法)时,应使用双括号:

(Map[String, Int]() /: entries)((r, c) => { r + ((c.name, r.get(c.name).map(_ + 1).getOrElse(1) )) })

我也改变了Int的计算,这在你的例子中看起来很有趣......

答案 1 :(得分:3)

因为+用于将字符串连接到字符串。在这种情况下,括号不是指元组,而是指参数。

Scala已将+用于其他内容,这会导致各种问题,就像您提到的那样。

+替换为updated,或使用->代替,

答案 2 :(得分:1)

r + (c.name, if (r.contains(c.name)) (c.name) + 1 else 1)

被解析为

r.+(c.name, if (r.contains(c.name)) (c.name) + 1 else 1)

因此,编译器会在+上查找带有2个参数的Map方法,但找不到它。我更喜欢双括号的形式(如Jean-Philippe Pellet建议的那样)

r + (c.name -> if (r.contains(c.name)) (c.name) + 1 else 1)

更新:

如果Pellet是正确的,最好写

r + (c.name -> r.getOrElse(c.name, 0) + 1)

(当然,詹姆斯·伊里的解决方案表达了同样的意图)。