使用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

最佳答案

您的尝试有一些问题,但是首先让我们看一个可行的实现:

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
您的代码中有两个主要错误:
  • PF定义的方式
  • (错误的假设),即empty是返回Nothing的“包罗万象”函数

  • 1.如何定义PartialFunction
    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”,因此很显然失败的原因。
    2.空无所获!
    直接从docs:

    您正在寻找的PartialFunction(嗯,它不再是部分内容了)是:
    val fallback: PartialFunction[Any, Unit] = { case _ => println("fallback") }
    
    或者-只是为了表明我们从错误中学到的东西-
    val fallback = PartialFunction[Any, Unit] { _ => println("fallback") }
    

    关于scala - orElse如何在PartialFunctions上工作,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/25372561/

    10-10 22:35