PartialFunction设计效率低下吗? [英] Is the PartialFunction design inefficient?
问题描述
这是我一段时间想知道的。我看到这种模式很多:
if(pf.isDefinedAt(in))pf(in)
code>
通过将其分解为两个单独的调用,所有在#isDefinedAt中评估的模式都将在#apply中进行评估。例如:
object Ex1 {
def unapply(in:Int):Option [String] = {$ b如果(在== 1中)一些(1)else无
}
}
对象Ex2 {
def unapply(in:Int):Option [String] = {
println(Ex2)
if(in == 2)Some(2)else None
}
}
val pf:PartialFunction [Int,String] = {
case Ex1(result)=>结果
案例Ex2(结果)=>结果
}
val in = 2
if(pf.isDefinedAt(in))pf(in)
$ b
Ex1
Ex2
Ex1
Ex2
res52:Any = 2
最糟糕的情况,您的模式与上次匹配的地方,您在调用PartialFunction时已经评估过模式/提取器两次。如果匹配自定义提取器,而不仅仅是一个简单的类或列表模式匹配(例如,如果您有一个提取器来解析XML文档并返回一些值对象),则这可能变得效率低下。
PartialFunction#lift受到相同的双重评估:
scala> pf.lift(2)
是副作用的话)。
Ex1
Ex2
Ex1
Ex2
res55:Option [String] =一些(2)
$ c $如果没有可能调用所有提取器两次,有条件地调用函数吗?
解决方案
首先,我们需要生成模式匹配代码两次,一次是apply,然后是isDefinedAt。其次,我们还需要执行两次代码,首先测试函数是否适用,然后再实际应用它。
您的问题的答案基本上是是,并且此行为(
PartialFunction
isDefinedAt
建议的新类型
FunctionWithDefault
没有isDefinedAt
并且有一个方法:trait FunctionWithDefault [-I,+ O] {
def applyOrElse [OO>:O](i:I,default :I => OO):OO
}
有点像
选项
sgetOrElse
方法。
我不得不说,像往常一样,我无法想象这种无效率会在绝大多数情况下带来任何表现问题。
This is something I've wondered about for a while. I see this pattern a lot:
if (pf.isDefinedAt(in)) pf(in)
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)
Which prints
Ex1 Ex2 Ex1 Ex2 res52: Any = 2
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 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?
解决方案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 usingPartialFunction
: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.
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 theisDefinedAt
is side-effecting).The new type being proposed,
FunctionWithDefault
has noisDefinedAt
and has a method:trait FunctionWithDefault[-I, +O] { def applyOrElse[OO >: O](i : I, default : I => OO) : OO }
which acts a bit like
Option
sgetOrElse
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屋!