PartialFunction设计效率低下吗?

Col*_*lin 13 functional-programming scala scala-2.8

这是我一段时间都想知道的事情.我看到这种模式很多:

if (pf.isDefinedAt(in)) pf(in)
Run Code Online (Sandbox Code Playgroud)

通过将其分解为两个单独的调用,在#isDefinedAt中计算的所有模式也将在#apply中进行评估.例如:

object Ex1 {
  def unapply(in: Int) : Option[String] = {
    println("Ex1")
    if (in == 1) Some("1") else None
  }
}

object Ex2 {
  def unapply(in: Int) : Option[String] = {
    println("Ex2")
    if (in == 2) Some("2") else None
  }
}

val pf : PartialFunction[Int,String] = {
  case Ex1(result) => result
  case Ex2(result) => result
}

val in = 2

if (pf.isDefinedAt(in)) pf(in)
Run Code Online (Sandbox Code Playgroud)

哪个打印

Ex1
Ex2
Ex1
Ex2
res52: Any = 2
Run Code Online (Sandbox Code Playgroud)

在最坏的情况下,您的模式最后匹配,在调用PartialFunction时,您已经两次评估了模式/提取器.当匹配不仅仅是简单的类或列表模式匹配的自定义提取器时,这可能会变得低效(例如,如果您有一个解析XML文档并返回一些值对象的提取器)

PartialFunction#lift遭受同样的双重评估:

scala> pf.lift(2)
Ex1
Ex2
Ex1
Ex2
res55: Option[String] = Some(2)
Run Code Online (Sandbox Code Playgroud)

有没有办法有条件地调用一个函数,如果它被定义而没有潜在地调用你的所有提取器两次?

oxb*_*kes 17

一个谈话继续下去关于这个 现在右边的上阶,内部邮件列表.Martin Odersky提出了一种新型:FunctionWithDefault.Martin不仅讨论了运行时惩罚,而且还讨论了使用以下内容的编译时间惩罚(类文件膨胀)PartialFunction:

首先,我们需要生成模式匹配代码两次,一次在apply中,然后再在isDefinedAt中生成.其次,我们还需要执行两次代码,首先测试函数是否适用,然后实际应用它.

您的问题的答案基本上是"是",并且PartialFunction由于向后兼容性问题(例如,如果isDefinedAt是副作用的话),此行为(of )也不会改变.

提出的新类型FunctionWithDefault没有isDefinedAt,有一个方法:

trait FunctionWithDefault[-I, +O] {
  def applyOrElse[OO >: O](i : I, default : I => OO) : OO
}
Run Code Online (Sandbox Code Playgroud)

这有点像Options getOrElse方法.

我不得不说,像往常一样,我无法想象这种低效率会在绝大多数情况下造成任何形式的性能问题.