本文介绍了PartialFunction 设计效率低下吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是我一直想知道的事情.我经常看到这种模式:

This is something I've wondered about for a while. I see this pattern a lot:

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

通过将其分解为两个单独的调用,所有在#isDefinedAt 中求值的模式也将在#apply 中求值.例如:

By breaking this up into two separate calls, all of the patterns that were evaluated in #isDefinedAt are then also evaluated in #apply. For example:

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 文档并返回一些值对象的提取器)

In the worst case, where your pattern matches last, you've evaluated your patterns/extractors twice when calling a PartialFunction. This could become inefficient when matching over custom extractors that did more than just a simple class or list pattern match (for example, if you had an extractor that parsed an XML document and returned some value objects)

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

PartialFunction#lift suffers from the same double-evaluation:

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

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

Is there a way to conditionally call a function if it is defined without potentially calling all of your extractors twice?

推荐答案

正在讨论这个问题现在scala-internals 邮件列表上.Martin Odersky 提出了一种新类型:FunctionWithDefault.Martin 不仅谈到了使用 PartialFunction 的运行时间损失,还谈到了编译时间损失(类文件膨胀):

There is a conversation going on about this right now on the scala-internals mailing list. Martin Odersky has suggested a new type: FunctionWithDefault. Martin talks not only of a run-time penalty, but a compile time penalty (of class file bloat) of using PartialFunction:

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

您的问题的答案基本上是是",并且这种行为(PartialFunction)不会因向后兼容性问题而改变(例如,如果 isDefinedAt 有副作用).

The answer to your question is essentially "yes" and and this behaviour (of PartialFunction) will not change either due to backwards-compatibility issues (for example, what if the isDefinedAt is side-effecting).

提议的新类型,FunctionWithDefault 没有 isDefinedAt 并且有一个方法:

The new type being proposed, FunctionWithDefault has no isDefinedAt and has a method:

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

这有点像 OptiongetOrElse 方法.

which acts a bit like Options getOrElse method.

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

I have to say that, as usual, I cannot imagine this inefficiency poses any sort of performance problem in the overwhelming majority of cases.

这篇关于PartialFunction 设计效率低下吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

07-16 13:09