Scala Map foreach

54

假设:

val m = Map[String, Int]("a" -> 1, "b" -> 2, "c" -> 3)
m.foreach((key: String, value: Int) => println(">>> key=" + key + ", value=" + value))

为什么编译器会抱怨?

error: type mismatch
found   : (String, Int) => Unit
required: (String, Int) => ?
7个回答

82

我不确定错误的原因,但您可以按照以下方式实现所需的功能:

m.foreach(p => println(">>> key=" + p._1 + ", value=" + p._2))

也就是说,foreach 接收的参数是一个函数,该函数以一对值为输入并返回 Unit,而不是以两个参数作为输入的函数。在本例中,p 的类型为 (String, Int)

另一种写法是:

m.foreach { case (key, value) => println(">>> key=" + key + ", value=" + value) }
在这种情况下,{ case ... } 块是一个部分函数。

这很好,更符合动态语言 obj.each {k,v => ...} 的方法,比元组 ._1, ._2 语法更易读。 - virtualeyes
只是好奇,第二次使用(case)是否有任何性能考虑?尝试为每个元素分配变量等。我想让我的代码既易读又尽可能快。 - endertunc

36

抱歉,我误读了文档,map.foreach需要一个带有元组参数的函数字面值!

所以

m.foreach((e: (String, Int)) => println(e._1 + "=" + e._2))

工作


4
考虑到类型是推断的,你可以这样简单地写:m.foreach(e => println(e._1 + "=" + e._2))。该代码用途为遍历并输出字典(Map)中的每个键值对。 - virtualeyes
能否显示完整的类型?有很多地图,我担心不知道具体是哪一个。 - Alexey Berezkin

19

你需要对 Tuple2 参数进行模式匹配,以将变量分配给它的子部分 keyvalue。你可以用很少的改动来实现:

m.foreach{ case (key: String, value: Int) => println(">>> key=" + key + ", value=" + value)} 

5
顺便说一下,您可以从键和值中移除类型注释。 - Rogach

14

这个令人困惑的错误信息是编译器的一个bug,应该在2.9.2版本中得到修复:


我刚刚检查了(通过编译https://github.com/paulbutcher/baderrormessage针对2.9.1和2.9.2)。我可以看到问题存在于2.9.1中,而在2.9.2中不存在。如果您仍然遇到该问题的示例,请重新打开错误报告? - Paul Butcher
我刚刚尝试了@(Eishay Smith)在下面回答中发布的代码(我相信这与问题中显示的完全相同),使用Scala 2.9.2(Java HotSpot 1.7.0 VM for Windows 64-bit),并且可以看到与他的帖子中显示的相同荒谬消息。 - Renato
以下是我从Git编译您的代码时发生的情况: 欢迎使用Scala 2.9.2版本(Java HotSpot(TM) 64-Bit Server VM,Java 1.7.0)。 输入表达式以进行评估。 键入:help获取更多信息。scala> class Foo extends Function2[Int, Int, Int] { | def apply(x: Int, y: Int) = x + y | override def tupled: (Int, Int) => Int = super.tupled | } <console>:9: 错误:类型不匹配; 找到:((Int, Int)) => Int 需要:(Int, Int) => Int override def tupled: (Int, Int) => Int = super.tupled ^ - Renato
1
那个错误信息是正确的。请注意,“found”行中有两组括号。这个bug在于它以前只打印了一组括号。如果你在2.9.1中尝试并比较输出,你会发现它们是不同的。 - Paul Butcher

5

非常好的问题!即使明确输入foreach方法,它仍然会给出非常不清晰的编译错误。虽然有解决方法,但我不明白为什么这个例子不起作用。

scala> m.foreach[Unit] {(key: String, value: Int) => println(">>> key=" + key + ", value=" + value)}
<console>:16: error: type mismatch;
 found   : (String, Int) => Unit
 required: (String, Int) => Unit
              m.foreach[Unit] {(key: String, value: Int) => println(">>> key=" + key + ", value=" + value)}
                                                         ^

1
文档中说参数是元组 -> 单元,所以我们可以很容易地做到这一点。
Map(1 -> 1, 2 -> 2).foreach(tuple => println(tuple._1 +" " + tuple._2)))

0

另一种方式:

Map(1 -> 1, 2 -> 2).foreach(((x: Int, y: Int) => ???).tupled)

然而,它需要显式类型注释,因此我更喜欢使用部分函数。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接