文章目录
什么是偏函数(partial function)
官方文档的定义:
所谓偏函数(也叫部分函数)与完全函数想对应,普通的方法都是完全函数,即 f(i:Int) = xxx 是将所有Int类型作为参数的,是对整个Int集的映射;而偏函数则是对部分数据的映射,是一种不为每个可能的输入值都提供答案的函数。 它仅提供自己接受数据的答案,并定义了它可以处理的数据。 在Scala中,还可以查询部分函数以确定它是否可以处理特定值。
为什么要使用偏函数有什么好处
1 在完全函数中我们定义一个除法的函数。
val divide = (x: Int) => 42 / x
2 当我们输入 0 的时候将会出现问题
scala> divide(0)
java.lang.ArithmeticException: / by zero
这时候我们通常使用一些异常的处理来解决这个问题
Scala允许将除法功能定义为PartialFunction
。 这样做时,还明确声明在输入参数不为零时定义了该函数:
val divide = new PartialFunction[Int, Int] {
def apply(x: Int) = 42 / x
def isDefinedAt(x: Int) = x != 0
}
有了 偏函数可以做一些使用前的测试
scala> divide.isDefinedAt(1)
res0: Boolean = true
scala> if (divide.isDefinedAt(1)) divide(1)
res1: AnyVal = 42
scala> divide.isDefinedAt(0)
res2: Boolean = false
在使用偏函数的时候不一定要按照最上面的那样去使用它,也可以写一个简单的用法来实现相同的功能。
val divide2: PartialFunction[Int, Int] = {
case d: Int if d != 0 => 42 / d
}
同样可以实现上面的功能
scala> divide2.isDefinedAt(0)
res0: Boolean = false
scala> divide2.isDefinedAt(1)
res1: Boolean = true
使用偏函数的好处:
1 可以实现将过滤操作在一个函数里实现。
看韩顺平老师的scala语言核心编程的时候有这样一个例子
给你一个集合 val list = List(1, 2, 3, 4, “abc”) ,请完成如下要求:
- 将集合 list 中的所有数字+1,并返回一个新的集合
- 要求忽略掉 非数字 的元素,即返回的 新的集合 形式为 (2, 3, 4, 5)
解决方式一 模式匹配
/**
* 模式匹配
* */
def addOne2( i :Any ):Any = {
i match {
case x:Int => x + 1
case _ =>
}
}
解决方式二 map 遍历 + filter 过滤
def caseDemo ={
//定义要遍历的列表
val list = List(1,2,3,4,"hello")
//先过滤然后 再去map
println(list.filter(_.isInstanceOf[Int]).map(_.asInstanceOf[Int]).map(i => i+1))
}
偏函数
val list = List(1, 2, 3, 4, "hello")
//定义一个偏函数
//1. PartialFunction[Any,Int] 表示偏函数接收的参数类型是 Any,返回类型是 Int
//2. isDefinedAt(x: Any) 如果返回 true ,就会去调用 apply 构建对象实例,如果是 false,过滤
//3. apply 构造器 ,对传入的值 + 1,并返回(新的集合)
val partialFun = new PartialFunction[Any,Int] {
override def isDefinedAt(x: Any) = { println("x=" + x)
x.isInstanceOf[Int]
}
override def apply(v1: Any) = {
println("v1=" + v1)
v1.asInstanceOf[Int] + 1}
}
//使用偏函数
//说明:如果是使用偏函数,则不能使用 map,应该使用 collect
//说明一下偏函数的执行流程
//1. 遍历 list 所有元素
//2. 然后调用 val element = if(partialFun-isDefinedAt(list 单个元素)) {partialFun-apply(list 单个元素) }
//3. 每得到一个 element,放入到新的集合,最后返回
val list2 = list.collect(partialFun)
println("list2" + list2)
偏函数的实现原理
PartialFunction是一个trait
trait PartialFunction[-A, +B] extends (A) => B
可以将=>符号视为一个转换器,在这种情况下,可以将(A)=> B解释为将类型A转换为结果类型B的函数。
Scala中的map与collect
在看scala 偏函数的时候其中的案例需要用到collect方法。不仅是要在工具箱中使用其他工具,还因为它们已在某些库(包括Scala集合库)的API中使用。
List(1, 3, 5, "seven") map { case i: Int => i + 1 } //won't work
//scala.MatchError: seven (of class java.lang.String)
List(1, 3, 5, "seven") collect { case i: Int => i + 1 } //it works
scala 中的map 和 collect 的区别
def map[B](f: (A) ⇒ B): List[B]
def collect[B](pf: PartialFunction[A, B]): List[B]