基础用法
首先我们总结下偏函数的定义:
- 只接受一个参数
- 输入参数类型范围的子集
- 可以显示使用
isDefinedAt方法指定输入参数的范围,可以使用apply方法
举个例子(这个例子暂时存在问题,实际情况是,我们基本不用这种定义):
val squareRoot: PartialFunction[Double, Double] = {
def apply(x: Double) = Math.sqrt(x)
def isDefinedAt(x: Double) = x >= 0
}
实际使用时,我们更多使用case的方式定义:
package example
object MyExample {
def main(args: Array[String]): Unit = {
val evenToPrint: PartialFunction[Int, String] = {
case x if x % 2 == 0 => s"$x is even number"
}
val res = evenToPrint(10)
println(res) // 10 is even number
}
}
如果我们传入奇数,则会抛出运行时异常,比如我们传入1,会有如下的异常:
[error] scala.MatchError: 1 (of class java.lang.Integer)
[error] at scala.PartialFunction$$anon$1.apply(PartialFunction.scala:369)
[error] at scala.PartialFunction$$anon$1.apply(PartialFunction.scala:367)
[error] at example.MyExample$$anonfun$1.applyOrElse(MyExample.scala:5)
[error] at example.MyExample$$anonfun$1.applyOrElse(MyExample.scala:5)
[error] at scala.runtime.AbstractPartialFunction.apply(AbstractPartialFunction.scala:35)
[error] at example.MyExample$.main(MyExample.scala:8)
[error] at example.MyExample.main(MyExample.scala)
[error] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
[error] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
[error] at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
[error] at java.base/java.lang.reflect.Method.invoke(Method.java:566)
[error] stack trace is suppressed; run last Compile / run for the full output
[error] (Compile / run) scala.MatchError: 1 (of class java.lang.Integer)
[error] Total time: 2 s, completed 2022年4月4日 上午9:24:09
错误中会有提示具体错误在哪一行,上面很明显在地4-5行提示错误。
偏函数组合
偏函数使用时,一般会有多个组合,并借助orElse和andThen这种执行链式组合。
首先看下orElse:
package example
object MyExample {
def main(args: Array[String]): Unit = {
val evenToString: PartialFunction[Int, String] = {
case x if x % 2 == 0 => s"$x is even number"
}
val oddToString: PartialFunction[Int, String] = {
case x if x % 2 == 1 => s"$x is odd number"
}
val numToString: PartialFunction[Int, String] = {
evenToString orElse oddToString
}
println(numToString(4))
println(numToString(5))
}
}
代码输出:
4 is even number
5 is odd number
注意这里补充一点, orElse是一个方法。
orElse可以连接多个偏函数,这里不再赘述。
如果我们想在命中偏函数执行下一个操作,可以借助andThen来实现,我们结合前面的orElse,看下例子:
package example
object MyExample {
def main(args: Array[String]): Unit = {
val negativeToPositive: PartialFunction[Int, Int] = {
case x if x < 0 => -x
}
val positiveTimes2: PartialFunction[Int, Int] = {
case x if x > 0 => x * 2
}
val zeroToOne: PartialFunction[Int, Int] = {
case 0 => 1
}
// 这里串联起来orElse
val numOp: PartialFunction[Int, Int] = {
zeroToOne orElse positiveTimes2 orElse negativeToPositive
}
val numToPrint: PartialFunction[Int, String] = {
case x => s"Final number is $x"
}
val numOpFinal: PartialFunction[Int, String] = {
numOp andThen numToPrint // 这里使用andThen
}
println(numOpFinal(0))
println(numOpFinal(10))
println(numOpFinal(-5))
}
}
代码输出:
Final number is 1
Final number is 20
Final number is 5