首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >orElse如何在PartialFunctions上工作

orElse如何在PartialFunctions上工作
EN

Stack Overflow用户
提问于 2014-08-19 05:48:28
回答 3查看 9.5K关注 0票数 9

使用定义在PartialFunction上的orElse方法,我得到了非常奇怪的行为(至少在我看来是这样

在我看来:

代码语言:javascript
复制
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中观察到的文字记录:

代码语言:javascript
复制
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的类型。

但这也不能像预期的那样工作:

代码语言:javascript
复制
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
EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2014-08-19 07:11:54

您的尝试有一些错误,但首先让我们看看一个有效的实现:

代码语言:javascript
复制
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

您的代码中有两个主要错误:

  1. 定义PF的方式
  2. (错误的)假设empty是一个返回Nothing

的“全部捕获”函数

1.如何定义PartialFunction

代码语言:javascript
复制
val right: PartialFunction[String, Unit] = {
  case "hello" => println("bye")
}

How not来定义它:

代码语言:javascript
复制
val wrong = PartialFunction[String, Unit] {
  case "hello" => println("bye")
}

如果你看看PartialFunction.apply的定义

代码语言:javascript
复制
def apply[A, B](f: A => B): PartialFunction[A, B] = { case x => f(x) }

您将看到它为任何x定义了一个分部函数,并对其应用了给定的f函数。现在,您的{ case "hello" => println("bye") }f参数,因此您大概会得到以下(显然是意想不到的) PartialFunction

代码语言:javascript
复制
val wrong: PartialFunction[String, Unit] = {
  case x => x match {
    case "hello" => println("bye")  
  }

因此,当您询问它是否已定义时,它将始终返回true,因为它是为任何字符串定义的:

代码语言:javascript
复制
wrong.isDefinedAt("hello") // true (ok)
wrong.isDefinedAt("whatever") // true (sure?)

但是当你尝试apply它的时候

代码语言:javascript
复制
wrong("hello") // bye (ok)
wrong("whatever") // MatchError (BOOM!)

你在内部的匹配上做得不够。

由于orElse根据isDefined的结果来决定是否调用"else“,因此它失败的原因是显而易见的。

2.空抓不到任何东西!

直接从docs

def empty[A, B]: PartialFunction[A, B]

具有空域的分部函数。任何调用空部分函数的尝试都会导致抛出scala.MatchError异常。

您正在寻找的PartialFunction (好吧,它实际上不再是部分的)是:

代码语言:javascript
复制
val fallback: PartialFunction[Any, Unit] = { case _ => println("fallback") }

或者-只是为了表明我们从错误中吸取教训-

代码语言:javascript
复制
val fallback = PartialFunction[Any, Unit] { _ => println("fallback") }
票数 28
EN

Stack Overflow用户

发布于 2014-08-19 06:22:33

您使用的是PartialFunction对象apply方法,其定义如下:

代码语言:javascript
复制
def apply[A, B](f: A => B): PartialFunction[A, B] = { case x => f(x) }

基本上它接受一个从AB的函数,并自动将其包装在一个case语句中,问题是你也在传递case,而我不是100%确定接下来会发生什么,你可以尝试将一个函数传递给apply,或者很容易你可以不使用apply方法来尝试:

代码语言:javascript
复制
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

您还可以扩展特征并实现applyisDefined,如here所示。

票数 2
EN

Stack Overflow用户

发布于 2014-08-19 06:22:32

PartialFunction.empty[A,B]相当于:

代码语言:javascript
复制
{
  case x: Nothing => x
}

(此类型选中,因为NothingAB的子类型。)

或者,等效地:

代码语言:javascript
复制
{
  // 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]意味着:

代码语言:javascript
复制
{ case "hello" => println("Bye") } orElse { /* no cases here */ }

这可以简化为:

代码语言:javascript
复制
{ case "hello" => println("Bye") }

代码语言:javascript
复制
{ case "hello" => println("Bye"); case x:Nothing => x }

因此MatchError是显而易见的。

注意,the documetation还提到empty总是抛出MatchError

根据我的猜测,您想要一个始终匹配的PartialFunction。在标准库中没有命名方法,但是为什么要有命名方法呢?您可以简单地编写

代码语言:javascript
复制
{ case _ => () }
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/25372561

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档