第5章 函数式编程

第5章 函数式编程

5.1 函数式编程思想

  1. 在之前的学习中,我们一直学习的就是面向对象编程,所以解决问题都是按照面向对象的方式来处理的。比如用户登陆,但是接下来,我们会学习函数式编程,采用函数式编程的思路来解决问题。scala编程语言将函数式编程和面向对象编程完美地融合在一起了。
  • 面向对象编程

分解对象,行为,属性,然后通过对象的关系以及行为的调用来解决问题

  • 函数式编程

    将问题分解成一个一个的步骤,将每个步骤进行封装(函数),通过调用这些封装好的步骤,解决问题。

5.2 函数基础

  1. 基本语法

    第5章 函数式编程_第1张图片

  2. 函数与方法的区别

    第5章 函数式编程_第2张图片

    package chapter05
    
    object Test01_FunctionAndMethod {
      // main方法,方法和函数差不多,可以统称为函数
      // 函数定义在任何地方,方法定义在类内
      def main(args: Array[String]): Unit = {
        // 1. 定义函数
        def sayHi(name: String): Unit = {
          println("hi, " + name)
        }
    
        // 调用函数
        sayHi("scc")
        // 2. 调用对象的方法
        Test01_FunctionAndMethod.sayHi("scc")
    
        val result = Test01_FunctionAndMethod.sayHello("Alice")
        println(result)
      }
    
      // 2. 定义对象的方法
      def sayHi(name: String): Unit = {
        println("Hi, " + name)
      }
    
      def sayHello(name: String): String = {
        println("Hi, " + name)
        "Hello"
      }
    
    }
    
    
  3. 函数的定义,六种情况

    package chapter05
    
    object Test01_FunctionDefine {
      def main(args: Array[String]): Unit = {
    
        // 定义函数
        def f1(): Unit = {
          println("1. 无参,无返回值")
        }
    
        println(f1())
    
        def f2(): Int = {
          println("2. 无参,有返回值")
          2
        }
    
        println(f2())
    
    
        def f3(name: String): Unit = {
          println("3. 有参,无返回值" + name)
        }
    
        println(f3("scc"))
    
        def f4(name: String): Int = {
          println("4. 有参,有返回值")
          2
        }
    
        println(f4("scc"))
    
        def f5(name1: String, name2: String): Int = {
          println("5. 多参,有返回值" + name1 + name2)
          2
        }
    
        //    f5("scc", "zyy")
        println(f5("scc", "zyy"))
    
        def f6(name1: String, name2: String): Unit = {
          println("6. 多参,无返回值" + name1 + name2)
        }
    
        println(f6("scc", "zyy"))
      }
    }
    
    
  4. 函数参数,4种用法

    package chapter05
    
    //函数参数特殊用法,四种
    object Test03_FunctionParameter {
      def main(args: Array[String]): Unit = {
        // 1. 可变参数
        def f1(str: String*): Unit = {
          println(str)
        }
    
        f1("scc")
        f1("scc", "zyy", "520")
    
    
        // 2. 多个参数,可变参数在后
        def f2(str1: String, str2: String*): Unit = {
          println("str1: " + str1 + " str2: " + str2)
        }
    
        f2("scc")
        f2("scc", "zyy", "520")
    
    
        // 3. 参数默认值,放在最后
        def f3(name: String = "atNanJing"): Unit = {
          println("name: " + name)
        }
    
        f3()
    
        // 4. 带名参数
        def f4(name: String = "zyy", age: Int): Unit = {
          println(s"name: ${name} age is ${age}")
        }
    
        f4(name = "scc", age = 21)
        f4(age = 21)
      }
    }
    
    
  5. 函数至简原则

    所谓的至简原则,其实就是Scala的编译器为了提高开发效率。帮助我们将函数声明中能简化的地方全部都进行了简化。也就是说将函数声明中那些能省的地方全部都省掉。所以简单来说就是:能省则省

    package chapter05
    
    object Test04_Simplify {
      def main(args: Array[String]): Unit = {
        // 定义函数
        def f0(name: String): String = {
          return name
        }
    
        println(f0("scc"))
    
    
        // 1. 省略return
        def f1(name: String): String = {
          name
        }
    
        println(f1("scc"))
    
    
        // 2. 如果函数体只有一行代码,则省略花括号
        def f2(name: String): String = name
    
        println(f2("scc"))
    
        // 3. 函数返回值如果能推断出来,则省略返回值类型,相当于数学函数f3(x)=x
        def f3(name: String) = name
    
        // 4. 如果定义了return,则不能省略返回值类型
        def f4(name: String): String = {
          return name
        }
    
        // 5. 如果函数声明为Unit,那么即使函数体使用return关键字,也不起作用
        def f5(name: String): Unit = {
          return name
        }
    
        // 6. 如果Scala期望无返回值类型,则等号可以省略,叫做过程
        def f6(name: String) {
          println(name)
        }
    
        // 7. 如果函数没有参数,但是声明的时候加上了小括号,那么调用的时候,小括号可加可不加
        def f7() {
          println("7. 如果函数没有参数,但是声明的时候加上了小括号,那么调用的时候,小括号可加可不加")
        }
    
        f7()
        f7
    
        // 8. 如果函数没有参数,那么声明的时候可以省略小括号,在调用的时候,小括号不能加
        def f8 {
          println("8. 如果函数没有参数,那么声明的时候可以省略小括号,在调用的时候,小括号不能加")
        }
    
        f8
    
        // 9. 如果不关系函数名称,只关心逻辑处理,则可以省略def和函数名称,此时为匿名函数或者lambda表达式,区别为=>
        (name: String) => {
          println(name)
        }
      }
    
    }
    
    

5.3 高阶函数-匿名函数

  1. 匿名函数lambda及简化原则

    package chapter05
    
    object Test05_Lambda {
      def main(args: Array[String]): Unit = {
        // 1. 函数类型,String => Unit
        val fun: String => Unit = (name: String) => {
          println(name)
        }
    
        fun("atguigu")
    
        println("===================================")
    
        // 2. 定义一个函数,以匿名函数作为参数传入
        def f(func: String => Unit): Unit = {
          func("匿名函数")
        }
    
        f(fun)
    
        // 3. 匿名函数作为参数传入,类似于传入数据处理逻辑op,处理已经准备好的数据
        f((name: String) => {
          println(name)
        })
    
    
        // 4. 匿名函数至简原则,匿名函数,参数类型可以省略,会根据形参自动推断
        f((name) => {
          println(name)
        })
    
    
        // 5. 匿名函数至简原则,匿名函数,只有一个参数,省略括号
        f(name => {
          println(name)
        })
    
        //6. 匿名函数至简原则, 匿名函数,函数体只有一行,大括号可以省略
        f(name => println(name))
    
    
        // 6. 匿名函数至简原则,匿名函数,如果参数只出现一次,则参数和lambda表达式箭头=>可以省略,并且后面参数用_代替
        f(println(_))
    
        // 7. 如果能够判断println是一个函数体,而不是调用语句,则省略下划线
        f(println)
    
    
        // 实际示例,定义一个“二元运算”函数,只操作1和2两个数,但是具体运算通过参数传入
        def dualFunctionOneAndTwo(func: (Int, Int) => Int): Int = {
          func(1, 2)
        }
    
        dualFunctionOneAndTwo((num1, num2) => {
          num1 + num2
        })
    
        dualFunctionOneAndTwo(_ * _)
    
      }
    
    }
    
    
  2. 函数高阶操作

    • 函数作为值进行传递,注意下划线_,此时为function对象
    • 函数作为参数进行传递
    • 函数作为函数返回值进行返回
    package chapter05
    
    // 函数作为值进行传递
    object Test06_HighOrderFunction {
      def main(args: Array[String]): Unit = {
        def f(n: Int): Int = {
          println("f调用")
          n + 1
        }
    
        def fun(): Int = {
          println("fun调用")
          1
        }
    
        val result: Int = f(123)
        println(result)
    
        //1. 函数作为值进行传递,注意下划线_,此时为function对象
        val f1: Int => Int = f
        val f2 = f _
    
        println(f1)
        println(f1(1))
        println(f2)
        println(f2(1))
    
        // 函数赋值
        val f3: () => Int = fun
        val f4: () => Int = fun _
    
        println(f3)
        println(f4)
    
    
        // 2. 函数作为参数进行传递
        // 定义二元运算参数
        def dualEval(op: (Int, Int) => Int, a: Int, b: Int): Int = {
          op(a, b)
        }
    
        println(dualEval((a, b) => {
          a + b
        }, a = 1, b = 2))
        println(dualEval((a, b) => {
          a - b
        }, a = 1, b = 2))
    
        // 3. 函数作为函数返回值进行返回
        def f5() = {
          def f6(a: Int) = {
            println("f6调用" + a)
          }
    
          f6 _ //将函数直接返回,而不是函数调用
        }
    
        val f7 = f5()
        println(f7)
        println(f7(10))
        // 函数科里化吧?
        println(f5()(10))
      }
    }
    
  3. 函数高阶操作实践

    package chapter05
    
    object Test07_Practice_CollectionOperation {
      def main(args: Array[String]): Unit = {
        // 对数组进行处理,将操作抽象出来,处理完毕之后的结果返回一个新的数组
        val arr = Array(1, 2, 3, 4, 5)
    
        // 对数组进行处理,将操作抽象出来,处理完毕之后的结果返回一个新的数组
        def arrayOperation(array: Array[Int], op: Int => Int): Array[Int] = {
          array.map(op)
        }
    
        // 定义一个加一操作
        val fun = (num: Int) => {
          num + 1
        }
    
        def addOne(num: Int): Int = {
          num + 1
        }
    
        arrayOperation(arr, fun).foreach(println)
        arrayOperation(arr, addOne).foreach(println)
      }
    
    }
    
    
  4. 函数柯里化和闭包

    第5章 函数式编程_第3张图片

    第5章 函数式编程_第4张图片

    闭包推荐使用柯里化写法

    第5章 函数式编程_第5张图片

  5. 递归 pass

  6. 控制抽象

    1. 传值参数

      第5章 函数式编程_第6张图片

    2. 传名参数,传入的是代码块

      注意a:=>Int 表示传入代码块,返回值为Int

      第5章 函数式编程_第7张图片

      直接传入代码块

      第5章 函数式编程_第8张图片

  7. 惰性加载 lazy

    函数​前面加了lazy关键字,和控制抽象差不多,可能节约资源吧

    第5章 函数式编程_第9张图片

    例子:

    第5章 函数式编程_第10张图片

    当调用两次时,result值被计算出来,因此不需要再次调用,此处和控制抽象中传名参数不一样

    第5章 函数式编程_第11张图片​​​

你可能感兴趣的:(scala,scala,开发语言)