3

我不认为这段代码应该工作,但它确实(在 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

它是如何工作的?我希望 aMatchError被扔进去res0

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

4

3 回答 3

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将其参数视为一个总函数,因此有关其定义位置的任何信息都将丢失。

于 2013-11-14T21:04:17.043 回答
2

orElse被定义,PartialFunction以便在未定义原始参数的情况下将参数视为后备。请参阅API

于 2013-11-14T08:53:58.163 回答
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

MatchError因此,当 pf 都不匹配时,您只会得到 a 。

于 2013-11-14T08:50:39.303 回答