Magic PartialFunction in Scala



我认为这段代码不应该工作,但它确实有效(在 Scala 2.10 中):

scala>     ((i: Int) => i.toString match {
     |        case s if s.length == 2 => "A two digit number"
     |        case s if s.length == 3 => "A three digit number"
     |     }): PartialFunction[Int,String]
res0: PartialFunction[Int,String] = <function1>
// other interactions omitted
scala> res0.orElse(PartialFunction((i: Int) => i.toString))
res5: PartialFunction[Int,String] = <function1>
scala> res5(1)
res6: String = 1

它是如何工作的?我希望MatchError被扔进res0.

Scala语言规范似乎没有明确记录应该如何解释res0

诀窍在于编译器不会将您的定义解释为转换为部分函数的总函数 - 它实际上首先创建了一个部分函数。您可以通过注意res0.isDefinedAt(1) == false 来验证。

如果您实际将总函数转换为分部函数,您将获得预期的行为:

scala> PartialFunction((i: Int) => i.toString match {
     |       case s if s.length == 2 => "A two digit number"
     |       case s if s.length == 3 => "A three digit number"
     |     })
res0: PartialFunction[Int,String] = <function1>
scala> res0 orElse ({ case i => i.toString }: PartialFunction[Int, String])
res1: PartialFunction[Int,String] = <function1>
scala> res1(1)
scala.MatchError: 1 (of class java.lang.String)
// ...

在此示例中,PartialFunction.apply将其参数视为总函数,因此有关其定义位置的任何信息都将丢失。

orElse是在PartialFunction上定义的,因此在未定义原始参数的情况下,参数被视为回退。请参阅接口。

你说如果res0不匹配,你想试试你的另一个pf。这本质上是如何工作的:

if (res0.isDefinedAt(1)) {
  res0(1)
} else {
  other(1)
}

orElse 调用创建 OrElse 的实例,该实例继承自 PartialFunction : https://github.com/scala/scala/blob/master/src/library/scala/PartialFunction.scala#L159

当你现在在这个OrElse上调用apply时,它将调用f1.applyOrElse(x, f2):https://github.com/scala/scala/blob/master/src/library/scala/PartialFunction.scala#L162

这将调用if (isDefinedAt(x)) apply(x) else f2(x):https://github.com/scala/scala/blob/master/src/library/scala/PartialFunction.scala#L117-L118

因此,只有当PF都不匹配时,您只会得到一个MatchError

相关内容

  • 没有找到相关文章

最新更新