这是我一段时间以来一直想知道的事情。我经常看到这种模式:

if (pf.isDefinedAt(in)) pf(in)


通过将其分成两个单独的调用,然后在#apply中也评估了在#isDefinedAt中评估的所有模式。例如:

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)


哪些印刷品

Ex1
Ex2
Ex1
Ex2
res52: Any = 2


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

PartialFunction#lift具有相同的双重评估:

scala> pf.lift(2)
Ex1
Ex2
Ex1
Ex2
res55: Option[String] = Some(2)


如果定义了某个函数而没有潜在地两次调用所有提取程序的方法,是否可以有条件地调用它?

最佳答案

scala-internals邮件列表上现在有a conversation going on about this。 Martin Odersky建议使用一种新类型:FunctionWithDefault。 Martin不仅谈到运行时的损失,而且还谈到使用PartialFunction的编译时间的损失(类文件膨胀):


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


问题的答案本质上是“是”,并且(PartialFunction的)这种行为也不会因向后兼容问题(例如,isDefinedAt具有副作用)而改变。

提出的新类型FunctionWithDefault没有isDefinedAt并具有一种方法:

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


有点像OptiongetOrElse方法。

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

10-04 19:14