PartialFunction 设计效率低下吗? [英] Is the PartialFunction design inefficient?

查看:25
本文介绍了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 中.其次,我们还需要执行两次代码,首先测试函数是否适用,然后实际应用.

First, we need to generate the pattern matching code twice, once in the apply and then again in the isDefinedAt. Second, we also need to execute the code twice, first to test whether the function is applicable, and then to actually apply it.

您的问题的答案基本上是是",并且这种行为(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 设计效率低下吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆