问题描述
这是我一直想知道的事情.我经常看到这种模式:
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
}
这有点像 Option
的 getOrElse
方法.
which acts a bit like Option
s 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 设计效率低下吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!