您的第二个示例失败,因为您向 map 提供了一个带有 2 个参数的函数,而 map 采用了一个带有 1 个参数的函数。
看一下,这是map 函数的(简化)签名:
def map[B, That](f: A => B): That
函数f 是您必须传递的函数才能进行转换。如您所见,它的类型为A => B,即接受单个参数。
现在看一下(简化的)zip 函数签名:
def zip [B](that : List[B]) : List[(A, B)]
它实际上产生了一个列表,其成员是元组。 2 个元素的元组如下所示:(A, B)。当您在元组列表上调用 map 时,您必须提供函数 f,该函数将 2 个元素的元组作为参数,就像您在第一个示例中所做的那样。
由于直接使用元组不方便,您可以使用模式匹配将元组成员的值提取到单独的变量中。
这里有一个 REPL 会话来说明这一点。
scala> List(1, 2, 3)
res0: List[Int] = List(1, 2, 3)
scala> List(2, 3, 4)
res1: List[Int] = List(2, 3, 4)
scala> res0 zip res1
res2: List[(Int, Int)] = List((1,2), (2,3), (3,4))
以下是使用模式匹配进行标准元组值提取的方法:
scala> res2.map(t => t match {
| case (x, y) => x * y
| })
res3: List[Int] = List(2, 6, 12)
需要注意的是,模式匹配需要一个偏函数作为参数。 IE。下面的表达式实际上是一个偏函数:
{
case (x, y) => x * y
}
部分函数在 Scala 中有自己的类型:trait PartialFunction[-A, +B] extends (A) => B,您可以阅读更多关于它的信息,例如,here。
偏函数是一个普通函数,因为它扩展了(A) => B,这就是为什么您可以将偏函数传递给map调用:
scala> res2.map { case (x, y) => x * y }
res4: List[Int] = List(2, 6, 12)
您实际上在这里使用了特殊的 Scala 语法,它允许函数调用(在我们的例子中为map),而无需在其参数周围加上括号。您也可以用括号将其写成如下:
scala> res2.map ({ case (x, y) => x * y })
res5: List[Int] = List(2, 6, 12)
最后两次调用完全没有区别。
在对它进行模式匹配之前,您不必声明传递给map 的匿名函数的参数,这实际上是Scala 的语法糖。当您调用res2.map { case (x, y) => x * y } 时,真正发生的是使用偏函数进行模式匹配。
希望这会有所帮助。