1.偏函数

1.基本介绍

  • 在对符合某个条件,而不是所有情况进行逻辑操作时,使用偏函数是一个不错的选择
  • 将包在大括号内的一组case语句封装为函数,我们称之为偏函数,它只对会作用于指定类型的参数或指定范围值的参数实施计算,超出范围的值会忽略(未必会忽略,这取决于你打算怎样处理)
  • 偏函数在Scala中是一个特质PartialFunction

2.快速入门

给定集合val list = List(1, 2, 3, 4, "abc") ,要求将集合list中的所有数字+1,并返回一个新的集合,要求忽略掉非数字 的元素,即返回的 新的集合 形式为 (2, 3, 4, 5)

方式1:使用map和filter

object exercise_002 {
def main(args: Array[String]): Unit = {
val list = List(1, 2, 3, 4, "abc")
//思路1,使用map+fliter的思路
def f1(n:Any): Boolean = {
n.isInstanceOf[Int]
}
def f2(n:Int): Int = {
n + 1
}
def f3(n:Any): Int ={
n.asInstanceOf[Int]
}
val list2 = list.filter(f1).map(f3).map(f2)
println("list2=" + list2) }
}

  输出

这种方式虽然能够解决问题,但是显得繁琐

方式2:使用模式匹配

object exercise_003 {
def main(args: Array[String]): Unit = {
def addOne( i : Any ): Any = {
i match {
case x:Int => x + 1
case _ =>
}
}
val list = List(1, 2, 3, 4, "abc")
val list2 = list.map(addOne)
println("list2=" + list2) }
}

  输出

这种方式存在一个缺点是输出的序列中存在"()",然而还去不掉。

方式3:使用偏函数

object exercise_004 {
def main(args: Array[String]): Unit = {
def f2: PartialFunction[Any, Int] = {
case i: Int => i + 1 // case语句可以自动转换为偏函数
}
val list2 = List(1, 2, 3, 4,"ABC").collect(f2)
println(list2) }
}

  输出

上面的 val list2 = List(1, 2, 3, 4,"ABC").collect(f2)还可以进一步简化

val list3=List(1, 2, 3, 4,"ABC").collect{case i:Int => i+1}

  

3.偏函数是如何工作的呢?为了说明该问题,看如下实例

object exercise_005 {
def main(args: Array[String]): Unit = {
val list = List(1, 2, 3, 4, "abc")
val addOne3= new PartialFunction[Any, Int] {//使用匿名子类
def isDefinedAt(any: Any) = if (any.isInstanceOf[Int]) true else false
def apply(any: Any) = any.asInstanceOf[Int] + 1
}
val list3 = list.collect(addOne3)
println("list3=" + list3)
}
}

  输出

执行过程解释:

  1. 使用构建特质的实现类(使用的方式是PartialFunction的匿名子类)
  2. PartialFunction 是个特质(看源码)
  3. 构建偏函数时,参数形式   [Any, Int]是泛型,第一个表示参数类型,第二个表示返回参数
  4. 当使用偏函数时,会遍历集合的所有元素,编译器执行流程时先执行isDefinedAt()如果为true ,就会执行 apply, 构建一个新的Int,对象返回
  5. 执行isDefinedAt() 为false 就过滤掉这个元素,即不构建新的Int对象.
  6. map函数不支持偏函数,因为map底层的机制就是所有循环遍历,无法过滤处理原来集合的元素
  7. collect函数支持偏函数

collect函数的声明语句,可以发现它所接收的参数就是偏函数

4.偏函数简化形式

声明偏函数,需要重写特质中的方法(isDefinedAt和Apply),有的时候会略显麻烦,而Scala其实提供了简单的方法。

“case语句可以自动转换为偏函数”,在上面的方式3中,我们使用的就是该特性。

2.作为参数的函数

函数作为一个变量传入到了另一个函数中,那么该作为参数的函数的类型是:function1,即:(参数类型) => 返回类型

看如下实例

def plus(x: Int) = 3 + x
val result1 = Array(1, 2, 3, 4).map(plus(_))
println(result1.mkString(","))

对于实例的说明

  • map(plus(_)) 中的plus(_) 就是将plus这个函数当做一个参数传给了map,_这里代表从集合中遍历出来的一个元素。
  • plus(_) 这里也可以写成 plus ,表示对 Array(1,2,3,4) 遍历,将每次遍历的元素传给plus的 x
  • 进行 3 + x 运算后,返回新的Int ,并加入到新的集合 result1中
  • def map[B, That](f: A => B) 的声明中的 f: A => B 一个函数

3.匿名函数

没有名字的函数就是匿名函数,可以通过函数表达式来设置匿名函数

val triple = (x: Double) => 3 * x

println(triple(3))

说明

  • (x: Double) => 3 * x 就是匿名函数
  • (x: Double) 是形参列表, => 是规定语法表示后面是函数体, 3 * x 就是函数体,如果有多行,可以 {} 换行写.
  • triple 是指向匿名函数的变量。

实例:编写一个匿名函数,可以返回2个整数的和,并输出该匿名函数的类型

object exercise_006 {
def main(args: Array[String]): Unit = {
val f1 = (n1: Int, n2: Int ) => {
println("匿名函数被调用")
n1 + n2
}
println("f1类型=" + f1)
println(f1(10, 30)) }
}

  输出结果

4.高阶函数

能够接受函数作为参数的函数,叫做高阶函数 (higher-order function)。可使应用程序更加健壮。

实例1:定义一个高阶函数,参数能够接收函数和普通数据类型

object exercise_007 {
def main(args: Array[String]): Unit = {
//test 就是一个高阶函数,它可以接收f: Double => Double
def test(f: Double => Double, n1: Double) = {
f(n1)
}
//sum 是接收一个Double,返回一个Double
def sum(d: Double): Double = {
d + d
}
val res = test(sum, 6.0)
println("res=" + res)//12
}
}

  

高阶函数可以返回函数类型

def minusxy(x: Int) = {
(y: Int) => x - y //匿名函数
}
val result3 = minusxy(3)(5) //函数柯里化,先传入参数3,得到(y:Int)=3-y,再传入5,得到3-5=-2,最后返回计算结果
println(result3)

说明: def minusxy(x: Int) = (y: Int) => x - y

  • 函数名为 minusxy
  • 该函数返回一个匿名函数  (y: Int) = > x -y

说明val result3 = minusxy(3)(5)

  • minusxy(3)执行minusxy(x: Int)得到 (y: Int) => 3 - y 这个匿名函
  • minusxy(3)(5)执行 (y: Int) => x - y 这个匿名函数
  • 也可以分步执行: val f1 = minusxy(3);   val res3 = f1(5)

5.类型推断

1.基本介绍

参数推断省去类型信息(在某些情况下[需要有应用场景],参数类型是可以推断出来的,如list=(1,2,3) list.map()   map中函数参数类型是可以推断的),同时也可以进行相应的简写。

2.参数类型推断写法说明

  • 参数类型是可以推断时,可以省略参数类型
  • 当传入的函数,只有单个参数时,可以省去括号
  • 如果变量只在=>右边只出现一次,可以用_来代替

3.实例:将集合中每个元素的值加上1,并返回值。观察演化过程

object exercise_009 {
def main(args: Array[String]): Unit = {
val list = List(1, 2, 3, 4)
println(list.map((x:Int)=>x + 1)) //(2,3,4,5)
println(list.map((x)=>x + 1))
println(list.map(x=>x + 1))
println(list.map(_ + 1))
val res = list.reduce(_+_)
}
} 

说明

  • map是一个高阶函数,因此也可以直接传入一个匿名函数,完成map
  • 当遍历list时,参数类型是可以推断出来的,可以省略数据类型Int,println(list.map((x)=>x + 1))
  • 当传入的函数,只有单个参数时,可以省去括号,println(list.map(x=>x + 1))
  • 如果变量只在=>右边只出现一次,可以用_来代替,println(list.map(_ + 1))

6.函数柯里化

1. 基本介绍

  • 函数编程中,接受多个参数的函数都可以转化为接受单个参数的函数,这个转化过程就叫柯里化
  • 柯里化就是证明了函数只需要一个参数而已。
  • 不用设立柯里化存在的意义这样的命题。柯里化就是以函数为主体这种思想发展的必然产生的结果。(即:柯里化是面向函数思想的必然产生结果)

2.函数柯里化快速入门

编写一个函数,接收两个整数,可以返回两个数的乘积,要求:

  • 使用常规的方式完成
  • 使用闭包的方式完成
  • 使用函数柯里化完成
object exercise_010 {
def main(args: Array[String]): Unit = {
//说明
def mul(x: Int, y: Int) = x * y
println(mul(10, 10))
def mulCurry(x: Int) = (y: Int) => x * y
println(mulCurry(10)(9))
def mulCurry2(x: Int)(y:Int) = x * y
println(mulCurry2(10)(8))
}
}

  输出结果

3.使用函数柯里化

比较两个字符串在忽略大小写的情况下是否相等,注意,这里是两个任务:

  • 全部转大写(或小写)
  • 比较是否相等

针对这两个操作,我们用一个函数处理的思想,其实也变成了两个函数处理的思想(柯里化)

方式1: 简单的方式,使用一个函数完成.

def eq2(s1: String)(s2: String): Boolean = {
s1.toLowerCase == s2.toLowerCase
}

方式2:使用稍微高级的用法(隐式类):形式为 str.方法()

object exercise_011 {
def main(args: Array[String]): Unit = {
def eq(s1: String, s2: String): Boolean = {
s1.equals(s2)
}
implicit class TestEq(s: String) {
// 体现了将比较字符串的问题,分解成了两个任务完成
// 1.checkEq完成转换大小写
// 2.f函数完成比较任务
def checkEq(ss: String)(f: (String, String) => Boolean): Boolean = {
f(s.toLowerCase, ss.toLowerCase)
}
}
val str1 = "HellO"
print(str1.checkEq("HELLO")(_.equals(_)))
}
}

  

Scala中的函数高级使用的更多相关文章

  1. 【Scala篇】--Scala中的函数

    一.前述 Scala中的函数还是比较重要的,所以本文章把Scala中可能用到的函数列举如下,并做详细说明. 二.具体函数 1.Scala函数的定义 def fun (a: Int , b: Int ) ...

  2. Scala中的函数

    Scala中的函数 提纲 1.Scala中的函数简介 2.Scala中的函数的各种写法 1.Scala中的函数简介 =================== Scala是函数式编程和面向对象式编程的混合 ...

  3. Scala中的函数表达式

    最近看Spark的东西,由于之前没有接触过lambda函数表达式,所以搜了点资料,特地纪录在此 Scala中的Lambda表达式 在函数式编程中,函数是基本的构造块.Scala融合了java中的面向对 ...

  4. 大数据学习之Scala中main函数的分析以及基本规则(2)

    一.main函数的分析 首先来看我们在上一节最后看到的这个程序,我们先来简单的分析一下.有助于后面的学习 object HelloScala { def main(args: Array[String ...

  5. Scala 中 构造函数,重载函数的执行顺序

    在调试scala在线开发教程(http://www.imobilebbs.com/wordpress/archives/4911)的过程中看到了以下代码,但是这段代码无论怎么调试都无法成功. abst ...

  6. Scala中的构造器和高阶函数

    构造器 在定义类时可以定义主构造器.主构造器可以同时声明字段. /** * 主构造器 * @author Administrator */ //在scala中,类和方法交织在一起 class Test ...

  7. scala中的高阶函数

    版权申明:转载请注明出处. 文章来源:http://bigdataer.net/?p=332 排版乱?请移步原文获得更好阅读体验 1.scala中的函数 scala是一门面向对象和函数式编程相结合的语 ...

  8. Scala中的Implicit详解

    Scala中的implicit关键字对于我们初学者像是一个谜一样的存在,一边惊讶于代码的简洁, 一边像在迷宫里打转一样地去找隐式的代码,因此我们团队结合目前的开发工作,将implicit作为一个专题进 ...

  9. Scala 方法与函数

    Scala 方法与函数:http://www.runoob.com/scala/scala-functions.html Scala 有方法与函数,二者在语义上的区别很小.Scala 方法是类的一部分 ...

随机推荐

  1. js 绑定的键盘事件

    在全局绑定键盘事件 document.onkeydown = function(event){        //在全局中绑定按下事件 var e  = event  ||  window.e; va ...

  2. 【管理员已阻止你运行此应用】windows defender图标打叉,无法打开mmc.exe解决办法

    今天开机遇到一个奇怪的问题,发现windows defender图标上面打了个×: 打开按照系统提示需要restart服务,但是无法重启服务,会出现错误,然后尝试手动重启服务,准备打开管理控制台mmc ...

  3. 解决智慧城市发展困扰:Web 3D 智慧环卫 GIS 系统

    前言 智慧环卫,依托物联网技术与移动互联网技术,对环卫管理所涉及到的人.车.物.事进行全过程实时管理,合理设计规划环卫管理模式,提升环卫作业质量,降低环卫运营成本,用数字评估和推动垃圾分类管理实效.智 ...

  4. Android中service的生命周期

    Service作为Android四大组件 Service Activity ContentProvider BroadcastReceiver 之一,应用非常广泛,和Activity一样,Servic ...

  5. Java 线程池记录

    Java通过Executors提供四种线程池,分别为:newCachedThreadPool创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程.newFixe ...

  6. PHP array_udiff() 函数

    实例 比较两个数组的键值(使用用户自定义函数比较键值),并返回差集: <?phpfunction myfunction($a,$b){if ($a===$b){return 0;}return ...

  7. PHP date_sun_info() 函数

    ------------恢复内容开始------------ 实例 返回有关 2013 年 1 月 1 日,纬度 31.7667,经度 35.2333 的日出/日落和黄昏开始/黄昏结束的信息: < ...

  8. PHP zip_entry_filesize() 函数

    定义和用法 The zip_entry_filesize() 函数返回 zip 档案项目的原始文件尺寸(在压缩之前).高佣联盟 www.cgewang.com 语法 zip_entry_filesiz ...

  9. PHP registerXPathNamespace() 函数

    实例 为下一个 XPath 查询创建命名空间上下文: <?php$xml=<<<XML高佣联盟 www.cgewang.com<book xmlns:chap=" ...

  10. luogu4443 coci 2017 Dajave

    题目 给出一个长度为2^M的排列,元素分别是0, 1, 2, ... , 2^M -1. 选择其中某个非空连续子序列,然后允许交换这个排列中某两个不同的数,然后使得这个连续子序列的所有数的按位异或(b ...