使用定义在PartialFunction上的orElse方法,我得到了非常奇怪的行为(至少在我看来是这样
在我看来:
val a = PartialFunction[String, Unit] {
case "hello" => println("Bye")
}
val b: PartialFunction[Any, Unit] = a.orElse(PartialFunction.empty[Any, Unit])
a("hello") // "Bye"
a("bogus") // MatchError
b("bogus") // Nothing
b(true) // Nothing这是有道理的,但这并不是它的行为方式,我很难理解为什么,因为类型签名似乎表明了我上面所暴露的内容。
以下是我在Scala 2.11.2中观察到的文字记录:
Welcome to Scala version 2.11.2 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_11).
Type in expressions to have them evaluated.
Type :help for more information.
scala> val a = PartialFunction[String, Unit] {
| case "hello" => println("Bye")
| }
a: PartialFunction[String,Unit] = <function1>
scala> a("hello")
Bye
scala> a("bye")
scala.MatchError: bye (of class java.lang.String)
at $anonfun$1.apply(<console>:7)
at $anonfun$1.apply(<console>:7)
at scala.PartialFunction$$anonfun$apply$1.applyOrElse(PartialFunction.scala:242)
at scala.runtime.AbstractPartialFunction.apply(AbstractPartialFunction.scala:36)
... 33 elided
scala> val b = a.orElse(PartialFunction.empty[Any, Unit])
b: PartialFunction[String,Unit] = <function1>
scala> b("sdf")
scala.MatchError: sdf (of class java.lang.String)
at $anonfun$1.apply(<console>:7)
at $anonfun$1.apply(<console>:7)
at scala.PartialFunction$$anonfun$apply$1.applyOrElse(PartialFunction.scala:242)
at scala.PartialFunction$OrElse.apply(PartialFunction.scala:162)
... 33 elided注意val b的返回类型并没有扩展PartialFunction的类型。
但这也不能像预期的那样工作:
scala> val c = a.orElse(PartialFunction.empty[String, Unit])
c: PartialFunction[String,Unit] = <function1>
scala> c("sdfsdf")
scala.MatchError: sdfsdf (of class java.lang.String)
at $anonfun$1.apply(<console>:7)
at $anonfun$1.apply(<console>:7)
at scala.PartialFunction$$anonfun$apply$1.applyOrElse(PartialFunction.scala:242)
at scala.PartialFunction$OrElse.apply(PartialFunction.scala:162)
... 33 elided发布于 2014-08-19 07:11:54
您的尝试有一些错误,但首先让我们看看一个有效的实现:
scala> val a: PartialFunction[String, Unit] = { case "hello" => println("bye") }
a: PartialFunction[String,Unit] = <function1>
scala> val b: PartialFunction[Any, Unit] = { case _ => println("fallback") }
b: PartialFunction[Any,Unit] = <function1>
scala> val c = a.orElse(b)
c: PartialFunction[String,Unit] = <function1>
scala> c("hello")
bye
scala> c("foo")
fallback您的代码中有两个主要错误:
empty是一个返回Nothing的“全部捕获”函数
1.如何定义PartialFunction
val right: PartialFunction[String, Unit] = {
case "hello" => println("bye")
}How not来定义它:
val wrong = PartialFunction[String, Unit] {
case "hello" => println("bye")
}如果你看看PartialFunction.apply的定义
def apply[A, B](f: A => B): PartialFunction[A, B] = { case x => f(x) }您将看到它为任何x定义了一个分部函数,并对其应用了给定的f函数。现在,您的{ case "hello" => println("bye") }是f参数,因此您大概会得到以下(显然是意想不到的) PartialFunction
val wrong: PartialFunction[String, Unit] = {
case x => x match {
case "hello" => println("bye")
}因此,当您询问它是否已定义时,它将始终返回true,因为它是为任何字符串定义的:
wrong.isDefinedAt("hello") // true (ok)
wrong.isDefinedAt("whatever") // true (sure?)但是当你尝试apply它的时候
wrong("hello") // bye (ok)
wrong("whatever") // MatchError (BOOM!)你在内部的匹配上做得不够。
由于orElse根据isDefined的结果来决定是否调用"else“,因此它失败的原因是显而易见的。
2.空抓不到任何东西!
直接从docs
def empty[A, B]: PartialFunction[A, B]
具有空域的分部函数。任何调用空部分函数的尝试都会导致抛出scala.MatchError异常。
您正在寻找的PartialFunction (好吧,它实际上不再是部分的)是:
val fallback: PartialFunction[Any, Unit] = { case _ => println("fallback") }或者-只是为了表明我们从错误中吸取教训-
val fallback = PartialFunction[Any, Unit] { _ => println("fallback") }发布于 2014-08-19 06:22:33
您使用的是PartialFunction对象apply方法,其定义如下:
def apply[A, B](f: A => B): PartialFunction[A, B] = { case x => f(x) }基本上它接受一个从A到B的函数,并自动将其包装在一个case语句中,问题是你也在传递case,而我不是100%确定接下来会发生什么,你可以尝试将一个函数传递给apply,或者很容易你可以不使用apply方法来尝试:
scala> val a: PartialFunction[String, Unit] = {
| case "hello" => println("Bye")
| }
a: PartialFunction[String,Unit] = <function1>
scala> val b: PartialFunction[String, Unit] = {
| case _ => println("default")
| }
b: PartialFunction[String,Unit] = <function1>
scala> b("123")
default您还可以扩展特征并实现apply和isDefined,如here所示。
发布于 2014-08-19 06:22:32
PartialFunction.empty[A,B]相当于:
{
case x: Nothing => x
}(此类型选中,因为Nothing是A和B的子类型。)
或者,等效地:
{
// note: this is probably not a valid Scala code for a partial function
// but, as PartialFunction.empty's name suggests, it's an *empty* block
} 这不能与任何内容匹配。
.orElse可以理解为简单地连接来自两个PartialFunction的case语句列表。因此,在您的例子中,a.orElse(PartialFunction.empty[Any,Unit]意味着:
{ case "hello" => println("Bye") } orElse { /* no cases here */ }这可以简化为:
{ case "hello" => println("Bye") }或
{ case "hello" => println("Bye"); case x:Nothing => x }因此MatchError是显而易见的。
注意,the documetation还提到empty总是抛出MatchError。
根据我的猜测,您想要一个始终匹配的PartialFunction。在标准库中没有命名方法,但是为什么要有命名方法呢?您可以简单地编写
{ case _ => () }https://stackoverflow.com/questions/25372561
复制相似问题