6
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它们之间的唯一区别是它们的定义方式。谁能解释为什么结果如此不同?

提前致谢!!!

4

2 回答 2

6

核心区别在于,部分函数上的 isDefinedAt 没有像您在使用 PartialFunction.apply 方法的版本上所期望的那样定义。这就是为什么现在不推荐使用此方法的原因,PartialFunction.apply 旨在将总函数转换为部分函数,​​isDefinedAt 始终返回 true,这意味着它会认为它在您的示例中定义为 3,并尝试应用该函数而不是回退到您提供的偶数功能作为替代方案。

这在社区中提出了一个关于总功能与部分功能的共同痛点。PartialFunction 是 Function 的子类型,我猜在 OO 设计意义上它是一个带有附加方法(isDefinedAt)的函数,它告诉您该函数是否是为特定值定义的。许多人认为这是一个错误,因为在 Liskov 的意义上,Function 应该是 PartialFunction 的子类型,因为您可以在任何期望 PartialFunction 的地方使用 Function,但是如果您在期望 Function 的地方使用 PartialFunction 它将编译,那么可能会失败在运行时。我的感觉是因为可以认为 Function 有一个隐含的 isDefinedAt 始终返回 true,这将允许您更正关系并使 Function 成为 PartialFunction 的子类型。这在 PartialFunction 中达到了顶点。

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
于 2018-05-03T04:29:09.570 回答
2

在前两种情况下,您applyPartialFunction. 我知道,这听起来好像它应该工作。但这不是因为PartialFunction.apply应该阅读PartialFunction.fromTotalFunction

这是一个 scala 语言问题,如果我没记错的话(暂时找不到票,稍后再看),这个apply函数将fromTotalFunction在 Scala 2.13 中消失并被替换。

更新

我的意思是票是#6005

似乎自Scala 2.12.5PartialFunction.apply以来已弃用。

于 2018-05-03T04:22:52.020 回答