PartialFunction[-A, +B]函数的使用
转载记得注明出处
blog.csdn.net/isinstance/article/details/51809687
在Scala的文档中,是这样解释PartialFunction的:
PrartialFunction[-A,+B]
型的一元偏函数的域并不一定包括所有A型的值,函数isDefinedAt允许动态的测试如果函数的值在这个域内。
即使a:A
的isDefinedAt
返回true
,调用apply(a)
仍然有可能抛出异常,下面的代码是合法的。
调用者有责任调用isDefinedAt
在apply
之前,因为如果isDefinedAt
如果失败了,不能保证apply
将抛出一个错误来指示错误条件。
如果不抛出一个错误,结果的赋值可能是一个任意的值。
PartialFunction
和scala.Function1
最主要的区别在于,使用PartialFunction
可以选择输入,然后宣称在其域内要做的不同的事情。
scala的官方文档给了一个实例代码
val sample = 1 to 10 //创建一个Range从1到10
val isEven: PartialFunction[Int, String] = {
case x if x % 2 == 0 => x+ " is even" //匹配x,如果x能整除2的话,也就是如果x所偶数的话
}
val evenNumber = sample collect isEven //collect方法可以使用isDefinedAt来选择要收集的成员
val isOdd: PartialFunction[Int, String] = {
case x if x % 2 == 1 => x+ " is odd"
}
val numbers = sample map (isEven orElse isOdd)//方法orElse允许链接一个偏函数来处理超出声明域的输入
然后我们来实际测试一下代码
首先输入
val sample = 1 to 10
输出如下
scala> val sample = 1 to 10
sample: scala.collection.immutable.Range.Inclusive = Range(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
这一步不用过多的说明了
输入
val isEven: PartialFunction[Int, String] = {
case x if x % 2 == 0 => x+ " is even"
}
输出
isEven: PartialFunction[Int,String] = <function1>
然后我们试试这个
val evenNumber = sample collect isEven
输出
evenNumber: scala.collection.immutable.IndexedSeq[String] = Vector(2 is even, 4 is even, 6 is even, 8 is even, 10 is even)
可以看出,对sample
中的每个元素带进isEven
函数,然后再调用了collect
之后,输出所有的偶数
我们继续定义isOdd
然后输出
val numbers = sample map (isEven orElse isOdd)
输出
numbers: scala.collection.immutable.IndexedSeq[String] = Vector(1 is odd, 2 is even, 3 is odd, 4 is even, 5 is odd, 6 is even, 7 is odd, 8 is even, 9 is odd, 10 is even)
已经通过这两个函数自动将偶数和奇数标记了出来
而定义函数的时候的PartialFunction[Int, String]
指名我们要输入的是一个Int
类型,输出的是一个String
类型
现在我们来看一个在Programming Scala
书中的例子
//匹配s,如果s是String类型的话,输出Yes
}
val pf2: PartialFunction[Any, String] = {
case d: Double => "Yes"//匹配d,如果d是Double类型的话,输出Yes
}
val pf = pf1 orElse pf2//将这两个函数结合,得到一个新的偏函数
def tryPF(x: Any, f: PartialFunction[Any, String]): String = try {
f(x).toString
} catch {
case _: MatchError => "ERROR!"
}
def d(x: Any, f: PartialFunction[Any, String]) = f.isDefinedAt(x).toString
List("str", 3.14, 10) foreach {
x =>
printf("%-5s %-5s %-6s %-5s %-6s %-5s %-6s\n", x.toString, d(x, pf1), tryPF(x, pf1), d(x, pf2), tryPF(x, pf2), d(x, pf), tryPF(x, pf))
}
我们一步一步来测试代码
scala> val pf1: PartialFunction[Any, String] = {
| case s:String => "Yes"
| }
pf1: PartialFunction[Any,String] = <function1>
scala> val pf2: PartialFunction[Any, String] = {
| case d:Double => "Yes"
| }
pf2: PartialFunction[Any,String] = <function1>
scala> val pf = pf1 orElse pf2
pf: PartialFunction[Any,String] = <function1>
scala> def tryPF(x: Any, f: PartialFunction[Any, String]): String = try { f(x).toString } catch { case _:MatchError => "Error!" }
tryPF: (x: Any, f: PartialFunction[Any,String])String
scala> def d(x: Any, f: PartialFunction[Any, String]) = f.isDefinedAt(x).toString
d: (x: Any, f: PartialFunction[Any,String])java.lang.String
scala> List("str", 3.14, 10) foreach {
| x =>
| printf("%-5s %-5s %-6s %-5s %-6s %-5s %-6s\n", x.toString, d(x, pf1), tryPF(x, pf1), d(x, pf2), tryPF(x, pf2), d(x, pf), tryPF(x, pf))
| }
str true Yes false Error! true Yes
3.14 false Error! true Yes true Yes
10 false Error! false Error! false Error!
注意:
第一列的值str
, 3.14
, 10
都属于x.toString
生成的
由此可以看出,未输入字符串时候,pf1将会失败,未输入Double数字时,pf2会失败,如果给的是Int数字,两个都会失败
组合后的pf函数,对于字符串和Double都会成功,但是输入Int类型数字时,依旧会失败