函数和方法是编程的基本组成部分。它们帮助我们处理输入并为我们提供输出。
在这篇文章中,我们将通过Scala的例子来学习部分函数。
注意:不要把它与部分定义函数混淆。
什么是部分函数?
在英语中。 "部分"意思是不完整的东西。同样,一个局部函数是一个只适用于我们定义的输入值的一个子集的函数。
让我们通过一个例子来理解,我们创建一个函数来执行整数除法。
val divide: (Int, Int) => Int = (num: Int, den: Int) => num / den
上面的除法函数是一个局部函数,因为它没有为分母的所有可能的int值(即本例中的0)定义。
Scala中的PartialFunction特性
PartialFunction是Scala标准库中的一个特质。
一个PartialFunction[A, B]类型的局部函数是一个 一元函数其中域不一定包括A类型的所有值。 isDefinedAt允许动态地测试一个值是否在该函数的域中。
trait PartialFunction[-A, +B] extends (A => B) { ...... }
让我们来逐一分解定义的部分。
首先,它说一个PartialFunction是一个 一级函数即它只接受一个参数,且类型为A。
其次,我们没有定义函数是对于A型的所有可能值。
最后,我们可以检查该函数是否为某一特定值定义了 isDefinedAt函数。
有2种方法可以让我们用PartialFunction重写除法函数。
val betterDivide: Int => PartialFunction[Int, Int] = (num: Int) => {
new PartialFunction[Int, Int] {
override def isDefinedAt(den: Int): Boolean = den != 0
override def apply(den: Int): Int = num / den
}
}
还有另一种方式,我们可以定义上述除法函数。
第二个版本没有第一个版本那么啰嗦。
val betterDivide2: Int => PartialFunction[Int, Int] = (num: Int) => {
case den: Int if den != 0 => num / den
}
利用上述部分函数
这就是我们如何调用上述2个函数的变体。
// Invoking First Version
val divide4By: PartialFunction[Int, Int] = betterDivide(4) // 4: Numerator
if(divide4By.isDefinedAt(2)) println(divide4By(2)) // 2: Denominator
else println("Invalid Division")
// OUTPUT: 2
if(divide4By.isDefinedAt(0)) println(divide4By(0)) // 0: Denominator
else println("Invalid Division")
// OUTPUT: Invalid Division
// Invoking Second Version
val divide6By = betterDivide2(6)
if(divide6By.isDefinedAt(2)) println(divide6By(2))
else println("Invalid Division")
// OUTPUT: 3
if(divide6By.isDefinedAt(0)) println(divide6By(0))
else println("Invalid Division")
// OUTPUT: Invalid Division
串联部分函数
Scala标准库在PartialFunction trait中也提供了一些有用的函数。
1.orElse
// Method declaration
override def orElse[A1 <: A, B1 >: B](that: PartialFunction[A1, B1])
// Usage
partialFunction1 orElse partialFunction2
如果partialFunction1的 isDefined方法返回false,那么partialFunction2将被执行。
2.andThen
// Method declaration
override def andThen[C](k: B => C): PartialFunction[A, C]
// Usage
val divide6AndIncrement = betterDivide2(6) andThen(_ + 1)
if(divide6AndIncrement.isDefinedAt(2)) println(divide6AndIncrement(2))
else println("Invalid Division")
// OUTPUT: 4
andThen方法接收一个函数,并将其应用于部分函数的结果。
结论
在浏览完这篇文章后,希望读者能理解什么是部分函数。许多Scala库,如集合库和其他API,如 Akka使用了部分函数。
例如,Akka Actors中的Receive类型不过是Any => Unit的一个局部函数。