函数本身(pf.apply
)是不是真的两次评估,但其isDefinedAt
是与您定义的成功匹配两次评估。这意味着在初始PartialFunction
pf
评估两次unapply
-s和警卫。
顺便说存在Scalaz一个组合子,做了类似的事情:pf.first.andThen(_._1)
,但它基本上等同于你的定义。
你可以写一个小测试,看看是否pf.isDefinedAt
是两次评估,并与pfAdapter
几种可能的实现运行它:
object Unapply {
def unapply(s: String): Boolean = {
println(s"unapplying on $s")
s == "1"
}
}
val m = Map("1" -> 1, "2" -> 2)
def pf: PartialFunction[String, String] = {
case Unapply() => "11"
}
def pfAdapter1[A, B, T](pf: PartialFunction[A, B]): PartialFunction[(A, T), B] =
Function.unlift((t: (A, T)) => pf.lift(t._1))
def pfAdapter2[A, B, T](pf: PartialFunction[A, B]): PartialFunction[(A, T), B] =
new PartialFunction[(A, T), B] {
def isDefinedAt(arg: (A, T)) = pf.isDefinedAt(arg._1)
def apply(arg: (A, T)) = pf(arg._1)
}
def pfAdapter3[A, B, T](pf: PartialFunction[A, B]): PartialFunction[(A, T), B] = {
case (a,b) if pf.isDefinedAt(a) => pf(a)
}
def pfAdapter4[A, B, T](pf: PartialFunction[A, B]): PartialFunction[(A, T), B] = {
import scalaz.Scalaz._
pf.first.andThen(_._1)
}
println(m collect pfAdapter1(pf))
println(m collect pfAdapter2(pf))
println(m collect pfAdapter3(pf))
println(m collect pfAdapter4(pf))
和执行该代码如下结果:
unapplying on 1
unapplying on 2
List(11)
unapplying on 1
unapplying on 1
unapplying on 2
List(11)
unapplying on 1
unapplying on 1
unapplying on 2
List(11)
unapplying on 1
unapplying on 1
unapplying on 2
List(11)
所以第一次执行pfAdapter
:Function.unlift((t: (A, T)) => pf.lift(t._1))
实际上确实避免两次评估isDefinedAt
。
这工作,因为Map.collect
与PartialFunction.applyOrElse
实现,并为applyOrElse
状态的文档,即:
对于所有的部分功能文本编译器生成的 applyOrElse实现避免了模式 匹配器和双评估警卫。这使得applyOrElse为 高效实现许多操作和场景,如基础:
...
因此,如果密钥不存在,您可以处理异常情况?或者我错过了什么? –
不,我想要一个PartialFunction,它是在元组上定义的,它们的第一个元素作为map中的一个键存在。没有例外:) – Dima
那么它是如何部分?当第一个元素不存在时,期望的结果是什么? –