Scala中的Magic PartialFunction

时间:2013-11-14 08:40:21

标签: scala partialfunction

我认为这段代码不起作用,但它确实如此(在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

3 个答案:

答案 0 :(得分:3)

诀窍是编译器不会将您的定义解释为转换为部分函数的总函数 - 它实际上是首先创建部分函数。您可以通过注明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将其参数视为总函数,因此有关其定义位置的任何信息都将丢失。

答案 1 :(得分:2)

orElse上定义了

PartialFunction,以便在未定义原始对象时将该参数视为回退。请参阅the API

答案 2 :(得分:1)

你说如果res0不匹配,你想尝试其他的pf。这基本上是如何工作的:

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

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

现在,当您apply致电OrElse时,会致电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