13.1 偏函数(partial function)

  13.1.1 需求 -> 思考

      一个集合val list = List(1,2,3,4,"abc"),完成如下要求

        1) 将集合list中的所有数字+1,并返回一个新的集合

        2) 要求忽略掉非数字的元素,即返回的新的集合形式为(2,3,4,5)

  13.1.2 解决方式-filter+map返回新的集合,引出偏函数

  13.1.3 解决方式-模式匹配

object boke_demo01 {

  def main(args: Array[String]): Unit = {
//思路1 filter + map 方式解决
//虽然可以解决问题,但是麻烦. val list = List(1, 2, 3, 4, "hello")
// 先过滤,再map
println(list.filter(f1).map(f3).map(f2)) //思路2-模式匹配
//小结:虽然使用模式匹配比较简单,但是不够完美
val list2 = list.map(addOne2)
println("list2=" + list2) } //模式匹配
def addOne2(i: Any): Any = {
i match {
case x: Int => x + 1
case _ =>
}
} def f1(n: Any): Boolean = {
n.isInstanceOf[Int]
} def f2(n: Int): Int = {
n + 1
} //将Any->Int [map]
def f3(n: Any): Int = {
n.asInstanceOf[Int]
}
}

13.1.4 偏函数快速入门

    -使用偏函数解决前面的问题

    -案例演示

object boke_demo01 {

  def main(args: Array[String]): Unit = {
//使用偏函数解决
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)
}
}

  13.1.5 偏函数的小结

      1) 使用构建特质的实现类(使用的方式是PartialFunction的匿名子类)

      2) PartialFunction是个特质

      3) 构建偏函数时,参数形式[Any,Int]是泛型,第一个表示参数类型,第二个表示返回参数

      4) 当使用偏函数时,会遍历集合的所有元素,编译器执行流程时先执行isDefinedAt(),如果为true,就会执行apply,构建一个新的对象返回

      5) 执行isDefinedAt()为false就过滤掉这个元素,即不构建新的Int对象

      6) map函数不支持偏函数,因为map底层的机制就是所有循环遍历,无法过滤处理原来集合的元素

      7) collect函数支持偏函数

  13.1.6 偏函数的简写形式

object boke_demo01 {

  def main(args: Array[String]): Unit = {

    //可以将前面的案例的偏函数简写
def partialFun: PartialFunction[Any, Int] = {
//简写成case 语句
case i: Int => i + 1
case j: Double => (j * 2).toInt
} val list = List(1, 2, 3, 4, 1.2, 2.4, 1.9f, "hello")
val list2 = list.collect(partialFun)
println("list2=" + list2) //第二种简写形式
val list3 = list.collect {
case i: Int => i + 1
case j: Double => (j * 2).toInt
case k: Float => (k * 3).toInt
}
println("list3=" + list3) // (2,3,4,5) }
}

13.2 作为参数的函数

  13.2.1 基本介绍

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

  13.2.2 应用案例

object boke_demo01 {

  def main(args: Array[String]): Unit = {
def plus(x: Int) = 3 + x //说明
val result = Array(1, 2, 3, 4).map(plus(_))
println(result.mkString(",")) //4,5,6,7 //说明
//1. 在scala中,函数也是有类型,比如plus就是 <function1>
println("puls的函数类型function1" + (plus _)) }
}

  13.2.3 对案例演示的小结

      1) map(plus(_))中的plus(_)就是将plus这个函数当作一个参数传给了map,_这里代表从集合中遍历出来的一个元素

      2) plus(_)这里也可以写成plus表示对Array(1,2,3,4)遍历,将每次遍历的元素传给plus的x

      3) 进行 3+x 运算后,返回新的Int,并加入到新的集合result中

      4) def map[B,That](f:A=>B)的声明中的 f:A=>B 的一个函数

13.3 匿名函数

  13.3.1 基本介绍

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

  13.3.2 应用案例

object boke_demo01 {

  def main(args: Array[String]): Unit = {
//对匿名函数的说明
//1. 不需要写 def 函数名
//2. 不需要写返回类型,使用类型推导
//3. = 变成 =>
//4. 如果有多行,则使用{} 包括
val triple = (x: Double) => {
println("x=" + x)
3 * x
}
println("triple=" + triple(3)) // 9.0 }
}

13.4 高阶函数

  13.4.1 基本介绍

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

  13.4.2 高阶函数基本使用

object boke_demo01 {

  def main(args: Array[String]): Unit = {
def test(f: Double => Double, f2: Double => Int, n1: Double) = {
f(f2(n1)) // f(0)
} //sum 是接收一个Double,返回一个Double
def sum(d: Double): Double = {
d + d
} def mod(d: Double): Int = {
d.toInt % 2
} val res = test(sum, mod, 5.0) //
println("res=" + res) // 2.0 }
}

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

object boke_demo01 {

  def main(args: Array[String]): Unit = {

    //说明
//1. minusxy是高阶函数,因为它返回匿名函数
//2. 返回的匿名函数 (y: Int) => x - y
//3. 返回的匿名函数可以使用变量接收 def minusxy(x: Int) = {
(y: Int) => x - y //匿名函数
} //分步执行
//f1 就是 (y: Int) => 3 - y
val f1 = minusxy(3)
println("f1的类型=" + f1)
println(f1(1)) // 2
println(f1(9)) // -6 //也可以一步到位的调用
println(minusxy(4)(9)) // -5 }
}

13.5 参数(类型)推断

  13.5.1 基本介绍

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

  13.5.2 参数类型推断写法说明

      1) 参数类型是可以推断时,可以省略参数类型

      2) 当传入的函数,只有单个参数时,可以省去括号

      3) 如果变量只在=>右边只出现一次,可以用_来代替

  13.5.3 应用案例

object boke_demo01 {

  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)) //(2,3,4,5)
println(list.map(x => x + 1)) //(2,3,4,5)
println(list.map(_ + 1)) //(2,3,4,5) println(list.reduce(f1)) // 10
println(list.reduce((n1: Int, n2: Int) => n1 + n2)) //10
println(list.reduce((n1, n2) => n1 + n2)) //10
println(list.reduce(_ + _)) //10 val res = list.reduce(_ + _) } def f1(n1: Int, n2: Int): Int = {
n1 + n2
}
}

13.6 闭包

  13.6.1 基本介绍

      闭包就是一个函数和与其相关的引用环境组合的一个整体(实体)

  13.6.2 案例演示1

object boke_demo01 {

  def main(args: Array[String]): Unit = {

    //1.用等价理解方式改写 2.对象属性理解
def minusxy(x: Int) = (y: Int) => x - y
//f 函数就是闭包.
val f = minusxy(20)
println("f(1)=" + f(1)) // 19
println("f(2)=" + f(2)) // 18 }
}

      -对上述案例演示的小结和说明

        1) (y: Int) => x - y 返回的是一个匿名函数,因为该函数引用到函数外的x,那么该函数和x整体形成一个闭包。如:这里val f = minusxy(20)的f函数就是闭包

        2) 可以这样理解,返回函数是一个对象,而x就是该对象的一个字段,它们共同形成一个闭包

        3) 当多次调用f时(可以理解多次调用闭包),发现使用的是同一个x,所以x不变

        4) 在使用闭包时,主要搞清楚返回函数引用了函数外的哪些变量,因为它们会组合成一个整体(实体),形成一个闭包

  13.6.3 案例演示2

object boke_demo01 {

  def main(args: Array[String]): Unit = {

    /*
请编写一个程序,具体要求如下
1.编写一个函数 makeSuffix(suffix: String) 可以接收一个文件后缀名(比如.jpg),并返回一个闭包
2.调用闭包,可以传入一个文件名,如果该文件名没有指定的后缀(比如.jpg) ,则返回 文件名.jpg , 如果已经有.jpg后缀,则返回原文件名。
比如 文件名 是 dog =>dog.jpg
比如 文件名 是 cat.jpg => cat.jpg
3.要求使用闭包的方式完成
提示:String.endsWith(xx) */
//使用并测试
val f = makeSuffix(".jpg")
println(f("dog.jpg")) // dog.jpg
println(f("cat")) // cat.jpg }
def makeSuffix(suffix: String) = {
//返回一个匿名函数,回使用到suffix
(filename:String) => {
if (filename.endsWith(suffix)) {
filename
} else {
filename + suffix
}
}
}
}

13.7 函数柯里化(curry)

  13.7.1 基本介绍

      1) 函数编程中,接受多个参数的函数都可以转化为接受单个参数的函数,这个转化过程就叫柯里化

      2) 柯里化就是证明了函数只需要一个参数而已

  13.7.2 函数柯里化快速入门

  //编写一个函数,接收两个整数,可以返回两个数的乘积,要求:
//使用常规的方式完成
//使用闭包的方式完成
//使用函数柯里化完成 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))

  13.7.3 函数柯里化应用案例

object boke_demo01 {

  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"
println(str1.checkEq("HeLLO")(eq)) //在看一个简写形式
println(str1.checkEq("HeLLO")(_.equals(_))) }
}

13.8 控制抽象

  13.8.1 看一个需求

//如何实现将一段代码(从形式上看),作为参数传递给高阶函数,在高阶函数内部执行这段代码
//其使用的形式如 breakable{} var n = 10
breakable {
while (n <= 20) {
n += 1
if (n == 18) {
break()
}
}
}

  13.8.2 控制抽象基本介绍

      -控制抽象是这样的函数,满足如下条件

        1) 参数是函数

        2) 函数参数没有输入值也没有返回值

      -控制抽象应用案例(使用控制抽象实现了while语法)

object boke_demo01 {

  def main(args: Array[String]): Unit = {
//myRunInThread 就是一个抽象控制
//是没有输入,也没有输出的函数 f1: () => Unit
def myRunInThread(f1: () => Unit) = {
new Thread {
override def run(): Unit = {
f1() //只写了 f1
}
}.start()
} myRunInThread {
() =>
println("干活咯!5秒完成...")
Thread.sleep(5000)
println("干完咯!") } //简写形式
def myRunInThread2(f1: => Unit) = {
new Thread {
override def run(): Unit = {
f1 //只写了 f1
}
}.start()
} //对于没有输入,也没有返回值函数,可以简写成如下形式
myRunInThread2 {
println("干活咯!5秒完成...~~~")
Thread.sleep(5000)
println("干完咯!~~~")
} }
}

  13.8.3 进阶用法:实现类似while的until函数

object boke_demo01 {

  def main(args: Array[String]): Unit = {

    var x = 10
//说明
//1 函数名为 until , 实现了类似 while循环的效果
//2. condition: => Boolean 是后一个没有输入值,返回Boolean类型函数
//3. block: => Unit 没有输入值,也没有返回值
def mywhile(condition: => Boolean)(block: => Unit): Unit = {
//类似while循环,递归
if (!condition) {
block // x= 9 ,x = 8 x =7 ....
mywhile(condition)(block)
} } mywhile(x == 0) {
x -= 1
println("x=" + x)
} }
}

13. Scala函数式编程(高级部分)的更多相关文章

  1. 大数据技术之_16_Scala学习_09_函数式编程-高级

    第十三章 函数式编程-高级13.1 偏函数(partial function)13.1.1 提出一个需求,引出思考13.1.2 解决方式-filter + map 返回新的集合13.1.3 解决方式- ...

  2. 5. Scala函数式编程的基础

    5.1 函数式编程内容及介绍顺序说明 5.1.1 函数式编程内容 -函数式编程基础 函数定义/声明 函数运行机制 递归(难点,[最短路径,邮差问题,迷宫问题,回溯]) 过程 惰性函数和异常 -函数式编 ...

  3. 9、scala函数式编程-集合操作

    一.集合操作1 1.Scala的集合体系结构 // Scala中的集合体系主要包括:Iterable.Seq.Set.Map.其中Iterable是所有集合trait的根trai.这个结构与Java的 ...

  4. Scala函数式编程(三) scala集合和函数

    前情提要: scala函数式编程(二) scala基础语法介绍 scala函数式编程(二) scala基础语法介绍 前面已经稍微介绍了scala的常用语法以及面向对象的一些简要知识,这次是补充上一章的 ...

  5. scala 函数式编程之集合操作

    Scala的集合体系结构 // Scala中的集合体系主要包括:Iterable.Seq.Set.Map.其中Iterable是所有集合trait的根trai.这个结构与Java的集合体系非常相似. ...

  6. Scala函数式编程(六) 懒加载与Stream

    前情提要 Scala函数式编程指南(一) 函数式思想介绍 scala函数式编程(二) scala基础语法介绍 Scala函数式编程(三) scala集合和函数 Scala函数式编程(四)函数式的数据结 ...

  7. Scala函数式编程进阶

    package com.dtspark.scala.basics /** * 函数式编程进阶: * 1,函数和变量一样作为Scala语言的一等公民,函数可以直接赋值给变量: * 2, 函数更长用的方式 ...

  8. Scala函数式编程——近半年的痛并快乐着

    从9月初啃完那本让人痛不欲生却又欲罢不能的<七周七并发模型>,我差不多销声匿迹了整整4个月.这几个月里,除了忙着讨食,便是继续啃另一本"锯著"--<Scala函数 ...

  9. Scala实战高手****第5课:零基础实战Scala函数式编程及Spark源码解析

    Scala函数式编程 ----------------------------------------------------------------------------------------- ...

随机推荐

  1. Windows RDP的RCE漏洞分析和复现(CVE-2019-0708)

    0x00 漏洞描述 Windows系列服务器于2019年5月15号,被爆出高危漏洞,该漏洞影响范围较广如:windows2003.windows2008.windows2008 R2.windows ...

  2. springboot 启动停止脚本

    https://www.cnblogs.com/lovychen/p/6211209.html   参考 centos 转码解决方案: yum install dos2unix dos2unix ** ...

  3. IE浏览器下AJAX缓存问题导致数据不更新的解决办法

    一直知道使用ajax的时候,有的时候会出现数据缓存的问题,当时也没有深究,就是所有的简单粗暴的全部加上cache:false,或者使用在url处加上随机时间函数 今天无意间看见了为什么会出现缓存的原因 ...

  4. vue - 过滤器-钩子函数路由

    一.关于路由 1.使用vue router 本质上是声明一种可以通过路径进行 挂子,用子 找到对应的 template 进行页面渲染 <!DOCTYPE html> <html la ...

  5. Nginx下HTML页面POST请求静态JSON数据返回405状态

    在浏览器访问HTML页面,发现一些静态JSON数据没有显示,F12查看,如下图所示: 可以看到请求方式为POST 将请求链接复制在浏览器地址栏访问,可以正常请求到数据 F12查看,可以看到请求方式为G ...

  6. LCD编程_显示文字

    在上篇博客中,实现了画点操作,然后在画点的基础上实现了画线.画圆的操作.实际上显示文字也是在画点的基础上实现的. 文字是由点组成的,那么这些点阵是在哪里获得的呢? 随便打开一个内核文件,搜索font, ...

  7. 201671030126 赵佳平 实验十四 团队项目评审&课程学习总结

    项目 内容 这个作业属于那个课程 2016级计算机科学与工程学院软件工程(西北师范大学) 这个作业的要求在哪里 实验十四 团队项目评审&课程学习总结 作业学习目标 掌握软件项目评审会流程:反思 ...

  8. AtCoder Grand Contest 033 题解

    传送门 我比赛的时候怕不是在睡觉啊-- \(A\ Darker\ and\ Darker\) 我是不是想得太复杂了--根本没必要像我这样做吧-- 首先问题可以转化成令\(p_{i,j}\)表示到\(( ...

  9. hdu1005-Number Sequence-(循环节)

    题意:已知f(1) = 1, f(2) = 1, f(n) = (A * f(n - 1) + B * f(n - 2)) mod 7,给出A,B,n,求f(n) 题解:n巨大,循环肯定超时,在模7的 ...

  10. [KCOJ3393]上马

    题目描述 Description Chicken在IEC(International Equestrianism Competition(国际马术表演赛))惨跪,没有成功的上到马,他深刻的记得他的选手 ...