scala函数式编程 之偏函数(partial function)的简单使用

什么是偏函数(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”) ,请完成如下要求:

  1. 将集合 list 中的所有数字+1,并返回一个新的集合
  2. 要求忽略掉 非数字 的元素,即返回的 新的集合 形式为 (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]

scala 部分应用函数

partially applied function in scala
Programming in Scala 书中提到
部分应用函数是将 def 转换成函数值。
如果有一个局部函数,例如sum(a:Int,b:Int,c:Int):Int,则可以将其“包装”到一个函数值中,该函数值的apply方法具有相同的参数列表和结果类型 。

scala> def sum(a: Int, b: Int, c: Int) = a + b + c
sum: (a: Int,b: Int,c: Int)Int
scala> val a = sum _
a: (Int, Int, Int) => Int = <function3>
scala> a.apply(1, 2, 3)
res12: Int = 6
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值