orElse
PartialFunction
方法让我的行为非常离奇(至少在我看来)
在我看来:
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
答案 0 :(得分:28)
你的尝试有一些问题,但首先让我们看看一个有效的实施:
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
val right: PartialFunction[String, Unit] = {
case "hello" => println("bye")
}
如何不来定义它:
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”,因此很明显它失败的原因。
直接来自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") }
答案 1 :(得分:2)
您正在使用PartialFunction
对象应用方法,该方法已定义:
def apply[A, B](f: A => B): PartialFunction[A, B] = { case x => f(x) }
基本上它需要一个函数形式A
到B
并自动将它包装在一个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。
答案 2 :(得分:1)
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
的案例陈述列表。因此,在您的情况下,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 _ => () }