经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » Java相关 » Scala » 查看文章
13. Scala函数式编程(高级部分)
来源:cnblogs  作者:铖歌  时间:2019/5/20 9:01:27  对本文有异议

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 解决方式-模式匹配 

  1. object boke_demo01 {
  2.  
  3. def main(args: Array[String]): Unit = {
  4. //思路1 filter + map 方式解决
  5. //虽然可以解决问题,但是麻烦.
  6.  
  7. val list = List(1, 2, 3, 4, "hello")
  8. // 先过滤,再map
  9. println(list.filter(f1).map(f3).map(f2))
  10.  
  11. //思路2-模式匹配
  12. //小结:虽然使用模式匹配比较简单,但是不够完美
  13. val list2 = list.map(addOne2)
  14. println("list2=" + list2)
  15.  
  16.  
  17. }
  18.  
  19. //模式匹配
  20. def addOne2(i: Any): Any = {
  21. i match {
  22. case x: Int => x + 1
  23. case _ =>
  24. }
  25. }
  26.  
  27.  
  28. def f1(n: Any): Boolean = {
  29. n.isInstanceOf[Int]
  30. }
  31.  
  32. def f2(n: Int): Int = {
  33. n + 1
  34. }
  35.  
  36. //将Any->Int [map]
  37. def f3(n: Any): Int = {
  38. n.asInstanceOf[Int]
  39. }
  40. }

13.1.4 偏函数快速入门 

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

    -案例演示

  1. object boke_demo01 {
  2.  
  3. def main(args: Array[String]): Unit = {
  4. //使用偏函数解决
  5. val list = List(1, 2, 3, 4, "hello")
  6. //定义一个偏函数
  7. //1. PartialFunction[Any,Int] 表示偏函数接收的参数类型是Any,返回类型是Int
  8. //2. isDefinedAt(x: Any) 如果返回true ,就会去调用 apply 构建对象实例,如果是false,过滤
  9. //3. apply 构造器 ,对传入的值 + 1,并返回(新的集合)
  10. val partialFun = new PartialFunction[Any, Int] {
  11.  
  12. override def isDefinedAt(x: Any) = {
  13. println("x=" + x)
  14. x.isInstanceOf[Int]
  15. }
  16.  
  17. override def apply(v1: Any) = {
  18. println("v1=" + v1)
  19. v1.asInstanceOf[Int] + 1
  20. }
  21. }
  22.  
  23. //使用偏函数
  24. //说明:如果是使用偏函数,则不能使用map,应该使用collect
  25. //说明一下偏函数的执行流程
  26. //1. 遍历list所有元素
  27. //2. 然后调用 val element = if(partialFun-isDefinedAt(list单个元素)) {partialFun-apply(list单个元素) }
  28. //3. 每得到一个 element,放入到新的集合,最后返回
  29. val list2 = list.collect(partialFun)
  30. println("list2" + list2)
  31. }
  32. }

  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 偏函数的简写形式 

  1. object boke_demo01 {
  2.  
  3. def main(args: Array[String]): Unit = {
  4.  
  5. //可以将前面的案例的偏函数简写
  6. def partialFun: PartialFunction[Any, Int] = {
  7. //简写成case 语句
  8. case i: Int => i + 1
  9. case j: Double => (j * 2).toInt
  10. }
  11.  
  12. val list = List(1, 2, 3, 4, 1.2, 2.4, 1.9f, "hello")
  13. val list2 = list.collect(partialFun)
  14. println("list2=" + list2)
  15.  
  16. //第二种简写形式
  17. val list3 = list.collect {
  18. case i: Int => i + 1
  19. case j: Double => (j * 2).toInt
  20. case k: Float => (k * 3).toInt
  21. }
  22. println("list3=" + list3) // (2,3,4,5)
  23.  
  24. }
  25. }

13.2 作为参数的函数 

  13.2.1 基本介绍 

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

  13.2.2 应用案例 

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

  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 应用案例 

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

13.4 高阶函数 

  13.4.1 基本介绍 

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

  13.4.2 高阶函数基本使用 

  1. object boke_demo01 {
  2.  
  3. def main(args: Array[String]): Unit = {
  4. def test(f: Double => Double, f2: Double => Int, n1: Double) = {
  5. f(f2(n1)) // f(0)
  6. }
  7.  
  8. //sum 是接收一个Double,返回一个Double
  9. def sum(d: Double): Double = {
  10. d + d
  11. }
  12.  
  13. def mod(d: Double): Int = {
  14. d.toInt % 2
  15. }
  16.  
  17. val res = test(sum, mod, 5.0) //
  18. println("res=" + res) // 2.0
  19.  
  20. }
  21. }

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

  1. object boke_demo01 {
  2.  
  3. def main(args: Array[String]): Unit = {
  4.  
  5. //说明
  6. //1. minusxy是高阶函数,因为它返回匿名函数
  7. //2. 返回的匿名函数 (y: Int) => x - y
  8. //3. 返回的匿名函数可以使用变量接收
  9.  
  10. def minusxy(x: Int) = {
  11. (y: Int) => x - y //匿名函数
  12. }
  13.  
  14. //分步执行
  15. //f1 就是 (y: Int) => 3 - y
  16. val f1 = minusxy(3)
  17. println("f1的类型=" + f1)
  18. println(f1(1)) // 2
  19. println(f1(9)) // -6
  20.  
  21. //也可以一步到位的调用
  22. println(minusxy(4)(9)) // -5
  23. }
  24. }

13.5 参数(类型)推断 

  13.5.1 基本介绍 

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

  13.5.2 参数类型推断写法说明 

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

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

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

  13.5.3 应用案例 

  1. object boke_demo01 {
  2.  
  3. def main(args: Array[String]): Unit = {
  4.  
  5. val list = List(1, 2, 3, 4)
  6. println(list.map((x: Int) => x + 1)) //(2,3,4,5)
  7. println(list.map((x) => x + 1)) //(2,3,4,5)
  8. println(list.map(x => x + 1)) //(2,3,4,5)
  9. println(list.map(_ + 1)) //(2,3,4,5)
  10.  
  11.  
  12. println(list.reduce(f1)) // 10
  13. println(list.reduce((n1: Int, n2: Int) => n1 + n2)) //10
  14. println(list.reduce((n1, n2) => n1 + n2)) //10
  15. println(list.reduce(_ + _)) //10
  16. val res = list.reduce(_ + _)
  17.  
  18. }
  19.  
  20. def f1(n1: Int, n2: Int): Int = {
  21. n1 + n2
  22. }
  23. }

13.6 闭包 

  13.6.1 基本介绍 

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

  13.6.2 案例演示1 

  1. object boke_demo01 {
  2.  
  3. def main(args: Array[String]): Unit = {
  4.  
  5. //1.用等价理解方式改写 2.对象属性理解
  6. def minusxy(x: Int) = (y: Int) => x - y
  7. //f 函数就是闭包.
  8. val f = minusxy(20)
  9. println("f(1)=" + f(1)) // 19
  10. println("f(2)=" + f(2)) // 18
  11.  
  12. }
  13. }

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

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

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

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

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

  13.6.3 案例演示2 

  1. object boke_demo01 {
  2.  
  3. def main(args: Array[String]): Unit = {
  4.  
  5. /*
  6. 请编写一个程序,具体要求如下
  7. 1.编写一个函数 makeSuffix(suffix: String) 可以接收一个文件后缀名(比如.jpg),并返回一个闭包
  8. 2.调用闭包,可以传入一个文件名,如果该文件名没有指定的后缀(比如.jpg) ,则返回 文件名.jpg , 如果已经有.jpg后缀,则返回原文件名。
  9. 比如 文件名 是 dog =>dog.jpg
  10. 比如 文件名 是 cat.jpg => cat.jpg
  11. 3.要求使用闭包的方式完成
  12. 提示:String.endsWith(xx)
  13.  
  14. */
  15. //使用并测试
  16. val f = makeSuffix(".jpg")
  17. println(f("dog.jpg")) // dog.jpg
  18. println(f("cat")) // cat.jpg
  19.  
  20. }
  21. def makeSuffix(suffix: String) = {
  22. //返回一个匿名函数,回使用到suffix
  23. (filename:String) => {
  24. if (filename.endsWith(suffix)) {
  25. filename
  26. } else {
  27. filename + suffix
  28. }
  29. }
  30. }
  31. }

13.7 函数柯里化(curry)

  13.7.1 基本介绍  

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

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

  13.7.2 函数柯里化快速入门 

  1. //编写一个函数,接收两个整数,可以返回两个数的乘积,要求:
  2. //使用常规的方式完成
  3. //使用闭包的方式完成
  4. //使用函数柯里化完成
  5. def mul(x: Int, y: Int) = x * y
  6. println(mul(10, 10))
  7.  
  8. def mulCurry(x: Int) = (y: Int) => x * y
  9. println(mulCurry(10)(9))
  10.  
  11. def mulCurry2(x: Int)(y:Int) = x * y
  12. println(mulCurry2(10)(8))

  13.7.3 函数柯里化应用案例 

  1. object boke_demo01 {
  2.  
  3. def main(args: Array[String]): Unit = {
  4.  
  5. //这是一个函数,可以接收两个字符串,比较是否相等
  6. def eq(s1: String, s2: String): Boolean = {
  7. s1.equals(s2)
  8. }
  9.  
  10. //隐式类
  11. implicit class TestEq(s: String) {
  12. //体现了将比较字符串的事情,分解成两个任务完成
  13. //1. checkEq 完转换大小写
  14. //2. f函数完成比较任务
  15. def checkEq(ss: String)(f: (String, String) => Boolean): Boolean = {
  16. f(s.toLowerCase, ss.toLowerCase)
  17. }
  18. }
  19. val str1 = "hello"
  20. println(str1.checkEq("HeLLO")(eq))
  21.  
  22. //在看一个简写形式
  23. println(str1.checkEq("HeLLO")(_.equals(_)))
  24.  
  25. }
  26. }

13.8 控制抽象  

  13.8.1 看一个需求 

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

  13.8.2 控制抽象基本介绍 

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

        1) 参数是函数

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

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

  1. object boke_demo01 {
  2.  
  3. def main(args: Array[String]): Unit = {
  4. //myRunInThread 就是一个抽象控制
  5. //是没有输入,也没有输出的函数 f1: () => Unit
  6. def myRunInThread(f1: () => Unit) = {
  7. new Thread {
  8. override def run(): Unit = {
  9. f1() //只写了 f1
  10. }
  11. }.start()
  12. }
  13.  
  14. myRunInThread {
  15. () =>
  16. println("干活咯!5秒完成...")
  17. Thread.sleep(5000)
  18. println("干完咯!")
  19.  
  20. }
  21.  
  22. //简写形式
  23. def myRunInThread2(f1: => Unit) = {
  24. new Thread {
  25. override def run(): Unit = {
  26. f1 //只写了 f1
  27. }
  28. }.start()
  29. }
  30.  
  31. //对于没有输入,也没有返回值函数,可以简写成如下形式
  32. myRunInThread2 {
  33. println("干活咯!5秒完成...~~~")
  34. Thread.sleep(5000)
  35. println("干完咯!~~~")
  36. }
  37.  
  38. }
  39. }

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

  1. object boke_demo01 {
  2.  
  3. def main(args: Array[String]): Unit = {
  4.  
  5. var x = 10
  6. //说明
  7. //1 函数名为 until , 实现了类似 while循环的效果
  8. //2. condition: => Boolean 是后一个没有输入值,返回Boolean类型函数
  9. //3. block: => Unit 没有输入值,也没有返回值
  10. def mywhile(condition: => Boolean)(block: => Unit): Unit = {
  11. //类似while循环,递归
  12. if (!condition) {
  13. block // x= 9 ,x = 8 x =7 ....
  14. mywhile(condition)(block)
  15. }
  16.  
  17. }
  18.  
  19. mywhile(x == 0) {
  20. x -= 1
  21. println("x=" + x)
  22. }
  23.  
  24. }
  25. }

 

原文链接:http://www.cnblogs.com/zhanghuicheng/p/10876998.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号