Scala部分函数类型定义

时间:2018-05-03 03:13:47

标签: scala partialfunction

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函数按预期工作时抛出匹配错误。它们之间的区别仅在于它们的定义方式。任何人都可以解释为什么这样的结果差异?

提前致谢!!!

2 个答案:

答案 0 :(得分:6)

核心区别在于,未使用PartialFunction.apply方法在版本上定义部分函数的isDefinedAt。这就是为什么现在不推荐使用这个方法的原因,PartialFunction.apply意味着将一个总函数转换为一个部分函数,​​isDefinedAt总是返回true,这意味着它会认为它在你的例子中定义为3,并尝试应用该函数而不是回到你提供的偶数函数作为替代。

这引发了社区关于总功能与部分功能的共同痛点。 PartialFunction是Function的一个子类型,我想在OO设计意义上它是一个带有附加方法(isDefinedAt)的函数,它告诉你函数是否为特定值定义。许多人认为这是一个错误,因为在Liskov意义上,Function应该是PartialFunction的子类型,因为你可以在任何需要PartialFunction的地方使用Function,但是如果你使用PartialFunction,其中一个Function会被编译,那么可能会失败在运行时。我的感觉是因为Function可以被认为具有一个始终返回true的隐式isDefinedAt,这将允许您更正关系并使Function成为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

答案 1 :(得分:2)

在前两种情况下,您在apply的伴随对象中调用PartialFunction函数。我知道,这听起来好像应该 工作。但它并不是因为PartialFunction.apply应该读PartialFunction.fromTotalFunction

这是一个scala语言问题,如果我没记错的话(目前无法找到故障单,稍后会查看),这个apply函数将会被fromTotalFunction取代在Scala 2.13中。

<强>更新

我的意思是#6005

Scala 2.12.5开始,PartialFunction.apply似乎已被弃用。