val even: PartialFunction[Int, String] = PartialFunction[Int, String] {
case i if i % 2 == 0 => i + " is even"
}
val isEven: PartialFunction[Int, String] = {
case i if i % 2 == 0 => i + " is even"
}
val odd: PartialFunction[Int, String] = PartialFunction[Int, String] {
case x if x % 2 == 1 => x + " is odd"
}
val isOdd: PartialFunction[Int, String] = {
case x if x % 2 == 1 => x + " is odd"
}
val tot = even orElse odd
val tot2 = isEven orElse isOdd
println(tot(3))
println(tot2(3))
在此代码中tot
函数引发匹配错误tot2
而函数按预期工作。它们之间的唯一区别是它们的定义方式。谁能解释为什么结果会有这种差异?
提前谢谢!!
核心区别在于,部分函数上的isDefinedAt没有像您在使用PartialFunction.apply方法的版本上期望的那样定义。 这实际上就是为什么现在不推荐使用此方法的原因,PartialFunction.apply 旨在将一个总函数转换为一个部分函数,isDefinedAt 始终返回 true,这意味着它会认为它在您的示例中是为 3 定义的,并尝试应用该函数而不是回退到您作为替代方案提供的偶数函数。
这在社区中提出了一个关于总功能与部分功能的共同痛点。PartialFunction 是 Function 的一个子类型,我想在 OO 设计意义上,它是一个带有附加方法 (isDefinedAt( 的函数,它告诉您该函数是否为特定值定义。 许多人认为这是一个错误,因为在Liskov意义上,函数应该是PartialFunction的一个子类型,因为你可以在任何需要PartialFunction的地方使用函数,但是如果你使用PartialFunction,而它需要一个函数将编译,那么可能会在运行时失败。 我的感觉是,这是因为函数可以被认为是有一个隐式的isDefinedAt,它总是返回true,这将允许你纠正关系并使函数成为PartialFunction的子类型。 这在 PartialFunction.apply 中达到了顶峰,它期望一个总函数,并且由于这个期望将 isDefinedAt 定义为始终返回 true,但它不能强制执行该期望,所以如果你调用 PartialFunction.apply(somePartialFunction(,就会发生大多数程序员不会想到的坏事。
PartialFunction.apply Scaladoc
PartialFunction[Int, String]{...} is syntactic sugar for
PartialFunction[Int, String].apply({...})
要尽量减少:
val even: PartialFunction[Int, String] = PartialFunction[Int, String]{
case i if i % 2 == 0 => i + " is even"
}
val isEven: PartialFunction[Int, String] = {
case i if i % 2 == 0 => i + " is even"
}
println(even.isDefinedAt(3)) //true
println(isEven.isDefinedAt(3)) //false
在前两种情况下,您在PartialFunction
的配套对象中调用apply
函数。我知道,这听起来好像应该 工作。但这不是因为PartialFunction.apply
应该阅读PartialFunction.fromTotalFunction
.
这是一个 scala 语言问题,如果我没记错的话(目前找不到票证,稍后会看(,这个apply
函数将消失并被 Scala 2.13 中的fromTotalFunction
取代。
更新
我的意思是#6005
似乎自 Scala 2.12.5 以来,PartialFunction.apply
已经被弃用了。