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. Tp5 空模块、空控制器、空方法的处理

    1.空模块处理 如果是开启了路由 可直接找到route.php文件,具体的位置看个人放置的位置,在里面新增一个语句 '__miss__' => ['portal/index/errorMsg', ...

  2. echarts 折线图百分比 tooltip 实例 两种方法

    方法一 在知道有几个类型时:下面有五个类型 tooltip : { show : true, trigger: 'axis', formatter: '{b0}<br/>{a0}: {c0 ...

  3. java全套学习资料

    1.背景 技术需要大家的共同努力,在这里我将平时学习过的觉得比较好的资料分享给大家; 当然,最好的学习就是输出,与大家分享,在分享的资料中有的是自己的总结,有的是分享来自互联网,如果有侵权请联系删除; ...

  4. TL-WDN5200H无线usb网卡在Linux上的使用

    买了个TL-WDN5200H无线usb网卡,但是发现它居然不支持Linux,但是我有时需要在Linux上使用,这就尴尬了.于是到网上搜索资料,终于解决了这个问题. 首先编译安装:https://git ...

  5. vmware-vmx.exe进程应该怎么杀掉

    如何解决VMware-vmx.exe无法彻底删除的问题 遇见的问题就是 虚拟机一直黑屏,强制关机之后,无法再次打开的问题. 显示:无法创建新虚拟机: 无法打开配置文件 以独占方式锁定此配置文件失败.另 ...

  6. nginx 静态资源服务

    1.文件压缩 location ~ .*\.(jpg|gif|png)$ { gzip on(开启); gzip_http_version 1.1(版本); gzip_comp_level 2(压缩比 ...

  7. Kafka数据安全性、运行原理、存储

    直接贴面试题: 怎么保证数据 kafka 里的数据安全? 答: 生产者数据的不丢失kafka 的 ack 机制: 在 kafka 发送数据的时候,每次发送消息都会有一个确认反馈机制,确保消息正常的能够 ...

  8. Github api【Restful接口规范】

    Overview This describes the resources that make up the official GitHub REST API v3. If you have any ...

  9. LeetCode 987. Vertical Order Traversal of a Binary Tree

    原题链接在这里:https://leetcode.com/problems/vertical-order-traversal-of-a-binary-tree/ 题目: Given a binary ...

  10. 二分查找java实现

    二分查找也称折半查找(Binary Search),它是一种效率较高的查找方法.但是,折半查找要求线性表必须采用顺序存储结构,而且表中元素按关键字有序排列. 二分查找思路非常简单,由粗暴的遍历查找改为 ...