3分钟内了解Scala中的部分函数

208 阅读2分钟

函数和方法是编程的基本组成部分。它们帮助我们处理输入并为我们提供输出。

在这篇文章中,我们将通过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的一个局部函数。