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

问题描述

这是我一段时间想知道的。我看到这种模式很多:

  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)




解决方案

scala-internals 邮件列表中有关此 的一段对话。 Martin Odersky提出了一个新的类型: FunctionWithDefault 。 Martin不仅讨论运行时间惩罚,而且还讨论了使用 PartialFunction 的编译时惩罚(类文件膨胀):

您的问题的答案基本上是是,并且此行为( PartialFunction isDefinedAt 是副作用的话)。



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

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

有点像选项 s getOrElse 方法。

我不得不说,像往常一样,我无法想象这种无效率会在绝大多数情况下带来任何表现问题。


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 using PartialFunction:

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).

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
}

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设计效率低下吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

10-14 07:51