Scala为什么这段代码会编译?

时间:2018-05-05 13:43:03

标签: scala functional-programming

这是从Coursera在Scala课程中的函数式编程的第6周开始的。

我试图围绕下面的代码片段。如果charcode的参数列表中没有charCode,如何将map传递给字符串的(c: Char)方法呢?

/* define the map of numbers to letters */
val nmem = Map( '2' -> "ABC", '3' -> "DEF", '4' -> "GHI", '5' -> "JKL", '6' 
-> "MNO", '7' -> "PQRS", '8' -> "TUV", '9' -> "WXYZ")

 /* invert the map the get a map of letters to digits */
val charCode: Map[Char, Char] = for ((digit, str) <- nmem; ltr <- str) yield 
ltr -> digit

/* define a function that returns the numbers of a given word */
def wordCode(word: String): String = word.toUpperCase map charCode

我习惯将函数传递给map,如下所示:

  val s = "JAVA"
  val str = s map (lower)
  def lower(c: Char) = c.toLower

您可以看到lower将char作为参数

此外,Odersky教授提到“类Map [Key,Value]也扩展了Function类型Key =&gt;值,因此可以在任何地方使用地图”。这就是为什么上面的代码有效吗?如果有,怎么样?我似乎无法找到任何关于此的文件? “地图可以在任何地方都可以使用”是什么意思?

非常感谢,

3 个答案:

答案 0 :(得分:2)

你是对的。它有效,因为Map[A, B] 实现了 Function1[A, B]。字符串的map方法需要一个函数将每个字符转换为另一个字符。也就是Function1[Char, Char],可以写成Char => Char

当您使用map致电Map[Char, Char]时,编译器会检查它实际上是Char => Char,因为它实现了Function1[Char, Char]

如何实施?

您可以将Map[A, B]视为PartialFunction[A, B]。也就是说,为有限数量的输入实现的功能。 Map[A, B]只是从A类型的键到类型B的值的映射。因此,您的A => B函数实现为:如果map包含A类型的键,则返回其类型B的值。如果它不存在,则不为该A定义部分函数。

层次

使其成为可能的层次结构是:

  • Map实施MapLike
  • MapLike实施PartialFunction
  • PartialFunction实施Function1

然后,如果您查看MapLike,就会找到def isDefinedAt(key: K) = contains(key)。这告诉部分函数是否定义了给定值。然后,它还实现了def apply(key: K): V所需的Function1

答案 1 :(得分:2)

您可以将地图视为部分函数的特殊类型 - 部分均值,不一定是所有值都已定义。

也就是说,地图m = Map[S,T]也是S=>T类型的函数。

让我们举个例子

scala> val includes = Map( 1 -> true, 2->false, 3-> false, 4->true)
includes: scala.collection.immutable.Map[Int,Boolean] = Map(1 -> true, 2 -> false, 3 -> false, 4 -> true)

scala> (1 to 4).filter(includes)
res6: scala.collection.immutable.IndexedSeq[Int] = Vector(1, 4)

(如果缺少序列中的值,则会出现运行时错误。)

那么,在你的问题中,你是将Map charCode传递给map函数,你会问为什么它会编译?

Scala中的String是Java string的类型别名。但在Predef中,存在从StringStringWrapper的隐式转换(低优先级) - 将字符串转换为CharStringOps的序列(注入集合方法的更高优先级(如map)。您可以在strings的文档中阅读更多内容。

因此,Scala编译器将您的String视为Char的序列,map函数使用提供的“函数”(即charCode映射)转换每个成员。

答案 2 :(得分:1)

Map[A, B]延伸PartialFunction[A, B]。尽管这有点red-herring,但每个PartialFunction[A, B]也是一个函数A => B(如果无法找到密钥,它会抛出错误)。 map方法需要一个函数A => B,所以一切都很合适。

总结一下,

  • charCodeMap[Char, Char]
  • 因此它扩展了PartialFunction[Char, Char]
  • 因此它也是普通函数Char => Char
  • 它可以作为参数传递给string.map