函數本身(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
那麼它是如何部分?當第一個元素不存在時,期望的結果是什麼? –