这是我一直想知道的事情。我看到了很多这种模式:
if (pf.isDefinedAt(in)) pf(in)
通过将其分解为两个单独的调用,在#isDefinedAt中评估的所有模式也将在#apply中进行评估。例如:
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文档并返回一些值对象的提取器),这可能会变得低效。
PartialFunction#lift遭受同样的双重评估:
scala> pf.lift(2)
Ex1
Ex2
Ex1
Ex2
res55: Option[String] = Some(2)
如果定义了函数而没有可能调用所有提取器两次,是否有条件调用函数?
答案 0 :(得分:17)
scala-internals 邮件列表中现在有a conversation going on about this 。 Martin Odersky提出了一种新类型:FunctionWithDefault
。 Martin不仅讨论了运行时惩罚,还讨论了使用PartialFunction
的编译时间惩罚(类文件膨胀):
首先,我们需要生成模式匹配代码两次,一次在apply中,然后再次在isDefinedAt中。其次,我们还需要执行两次代码,首先测试函数是否适用,然后实际应用它。
您的问题的答案基本上是“是”,并且此行为(PartialFunction
)也不会因向后兼容性问题而改变(例如,如果isDefinedAt
是侧面的话,该怎么办? - 影响)。
提议的新类型,FunctionWithDefault
没有isDefinedAt
并且有方法:
trait FunctionWithDefault[-I, +O] {
def applyOrElse[OO >: O](i : I, default : I => OO) : OO
}
有点像Option
s getOrElse
方法。
我必须说,像往常一样,我无法想象在绝大多数情况下,这种低效率会带来任何性能问题。