• Scala


    函数式编程的崛起

    函数式编程中的“值不可变性”避免了对公共的可变状态进行同步访问控制的复杂问题,能够较好满足分布式并行编程的需求,适应大数据时代的到来。

    函数是第一等公民

    • 可以作为实参传递给另外一个函数
    • 可以作为返回值
    • 可以赋值给变量
    • 可以存储在数据结构里
      def greeting() = (name: String) => { s"Hello" + " " + name }
                                                      //> greeting: ()String => String
      greeting()("World")                            //> res0: String = Hello World
    
      def greeting2(age: Int) = (name: String) => { s"Hello $name, your age is $age" }
                                                      //> greeting2: (age: Int)String => String
      greeting2(29)("Anliven")                        //> res2: String = Hello Anliven, your age is 29
    

    函数类型和值

    在函数式编程中,函数的使用方式和其他数据类型的使用方式完全一致,可以像任何其他数据类型一样被传递和操作。
    也就是说,可以像定义变量那样去定义一个函数,函数也会有“值”,函数的“值”就是“函数字面量(Funciton Literal)”,也称为函数文字量函数常量。实际上,这个函数字面量其实就是一个匿名函数
    需要注意:
    • Scala语法要求函数的“值”采用“=>”而不是“=”。
    • 在Scala中,函数类型的格式为 A => B,表示一个接受类型A的参数,并返回类型B的函数。
      def test(x: Int): Int = { x + 1 }               //> test: (x: Int)Int
      def test1(x: Int) = x + 1                       //> test1: (x: Int)Int
      val test2: Int => Int = { (x: Int) => x + 1 }   //> test2  : Int => Int = testrepl$$$Lambda$8/290658609@c818063
      val test3 = { (x: Int) => x + 1 }               //> test3  : Int => Int = testrepl$$$Lambda$9/1057941451@75bd9247
    
      def test5(x: Int, y: Int) = x + y               //> test5: (x: Int, y: Int)Int
      var test6 = (x: Int, y: Int) => x + y           //> test6  : (Int, Int) => Int = testrepl$$$Lambda$10/1513712028@3cb5cdba
      test6(2, 6)  
    
    示例说明:
    第7行把函数"(x: Int, y: Int) => x + y"作为一个值(函数字面量)赋给test6变量。
    由此可见,Scala中的函数和普通变量的使用方式完全一致。

    匿名函数

    使用匿名函数(Anonymous Function),可以不需要给每个函数命名,大大简化代码编写工作。
    匿名函数的定义形式(也称为“Lamda表达式”):(参数) => {表达式}
    注意:如果参数只有一个,可省略参数的圆括号;如果表达式只有一行,可省略表达式的花括号。
      val myNum: Int => Int = (x: Int) => { x * 2 }   //> myNum  : Int => Int = testrepl$$$Lambda$3/2093176254@799f7e29
      val myNum2 = (x: Int) => x * 2                  //> myNum2  : Int => Int = testrepl$$$Lambda$9/804581391@c818063
      val myNum3: Int => Int = (x) => x * 2           //> myNum3  : Int => Int = testrepl$$$Lambda$10/1057941451@75bd9247
      myNum(3)                                        //> res0: Int = 6
      myNum2(3)                                       //> res1: Int = 6
      myNum3(3)                                       //> res2: Int = 6
          
      def test1(x: Int): Int = { x * x }              //> test1: (x: Int)Int
      def test2(x: Int) = x * x                       //> test2: (x: Int)Int
      (x: Int) => x * x                               //> res0: Int => Int = testrepl$$$Lambda$8/431687835@5ba23b66
      val test3 = (x: Int) => x * x                   //> test3  : Int => Int = testrepl$$$Lambda$9/804581391@c818063
      val test4: Int => Int = (x) => x * x            //> test4  : Int => Int = testrepl$$$Lambda$10/1057941451@75bd9247
      test1(3)                                        //> res1: Int = 9
      test2(3)                                        //> res2: Int = 9
      test3(3)                                        //> res3: Int = 9
      test4(3)                                        //> res4: Int = 9   
    
    示例说明:
    • 第1行:把匿名函数"(x: Int) => { x * 2 }"定义为一个值,赋值给myNum变量
    • 第2行:省略myNum2的类型声明“Int=>Int”,省略匿名函数的表达式花括号
    • 第3行:省略x的类型声明,省略匿名函数的表达式花括号
    注意:类型声明“Int=>Int”和x的类型声明,不可以同时省略,因为全部省略以后,解释器也无法推断出类型。
      def test1(x: Int, y: Int): Int = { x + y }      //> test1: (x: Int, y: Int)Int
      def test2(x: Int, y: Int) = x + y               //> test2: (x: Int, y: Int)Int
      (x: Int, y: Int) => x + y                       //> res0: (Int, Int) => Int = testrepl$$$Lambda$8/290658609@c818063
      var test3 = (x: Int, y: Int) => x + y           //> test3  : (Int, Int) => Int = testrepl$$$Lambda$9/1057941451@75bd9247
      var test4: (Int, Int) => Int = (x, y) => { x + y }
                                                      //> test4  : (Int, Int) => Int = testrepl$$$Lambda$10/2101440631@7dc36524
      test1(2, 6)                                     //> res1: Int = 8
      test2(2, 6)                                     //> res2: Int = 8
      test3(2, 6)                                     //> res3: Int = 8
      test4(2, 6)                                     //> res4: Int = 8
    

    闭包

    闭包是一个比较特殊的函数,反映了一个从开放到封闭的过程,返回值依赖于声明在函数外部的一个或多个变量。
    • 如果引用的变量是自由变量,没有绑定具体的值,那么此时这个函数是“开放的”。
    • 如果引用的自由变量被绑定具体的值后,不再是“自由变量”,从而构成一个封闭的函数,那么此时这个函数“被关闭”了。
    函数引用的外部变量,必须在函数外部给出值。
    闭包示例-1:
      var more = 1                                    //> more  : Int = 1
      val addMore = (x: Int) => x + more              //> addMore  : Int => Int = testrepl$$$Lambda$9/240650537@1cd072a9
      addMore(10)                                     //> res0: Int = 11
      more = 9
      addMore(10)                                     //> res1: Int = 19
    
    示例说明:
    函数定义“val addMore = (x: Int) => x + more”中,引用了没有在函数中定义的外部变量more,而more是一个自由变量,还没有绑定具体的值,此时这个函数是“开放的”;而变量x是一个已在函数中明确定义的变量,只有在调用的时候才被赋值。
    外部变量more确定具体值(“ var more = 1”)以后,那么函数addMore中的more变量也就被绑定具体值了,不再是“自由变量”,此时这个函数是“关闭的”。
    另外,每次addMore函数被调用时都会创建一个新闭包。每个闭包都会访问闭包创建时活跃的more变量。
    闭包示例-2:
      def plusStep(step: Int) = (num: Int) => num + step
                                                      //> plusStep: (step: Int)Int => Int
      val myFunc = plusStep(3)                        //> myFunc  : Int => Int = testrepl$$$Lambda$8/209813603@2f7c7260
      println(myFunc(10))                             //> 13
    
    示例说明:
    step是一个自由变量,它的值只有在运行的时候才能确定,num的类型是确定的,num的值只有在调用的时候才被赋值。
    这样的函数,被称为“闭包”,它反映了一个从开放到封闭的过程。

    高阶函数

    用函数作为形参或返回值的函数,称为高阶函数。
    也就是说,高阶函数就是一个接受其他函数作为参数或者返回一个函数的函数。
    高阶函数示例-1:
      def f(x: Int, y: Int) = x + y                  //> f: (x: Int, y: Int)Int
      def operate(f: (Int, Int) => Int) = { f(4, 4) } //> operate: (f: (Int, Int) => Int)Int
      operate(f) 
    
    示例说明:函数operate是一个接受函数参数的函数,因此是一个高阶函数。
    高阶函数示例-2:
      //给定两个数区间中的所有整数求和
      def sumInts(a: Int, b: Int): Int = {
        if (a > b) 0 else a + sumInts(a + 1, b)
      }                                               //> sumInts: (a: Int, b: Int)Int
      sumInts(1, 5)                                   //> res0: Int = 15
    
      //定义了一个新的函数sum,以函数f为参数
      def sum(f: Int => Int, a: Int, b: Int): Int = {
        if (a > b) 0 else f(a) + sum(f, a + 1, b)
      }                                               //> sum: (f: Int => Int, a: Int, b: Int)Int
      //定义了一个新的函数self,该函数的输入是一个整数x,然后直接输出x自身
      def self(x: Int): Int = x                       //> self: (x: Int)Int
      //重新定义sumInts函数
      def sumInts2(a: Int, b: Int): Int = sum(self, a, b)
                                                      //> sumInts2: (a: Int, b: Int)Int
      sumInts2(1, 5)                                  //> res1: Int = 15
    
    示例说明:函数sum的参数类型是(Int=>Int, Int, Int),结果类型是Int,也就是说函数sum是一个接受函数参数的高阶函数。
    高阶函数示例-3:
      def sum(f: Int => Int, a: Int, b: Int): Int = {
        if (a > b) 0 else f(a) + sum(f, a + 1, b)
      }                                               //> sum: (f: Int => Int, a: Int, b: Int)Int
    
      def self(x: Int): Int = x                       //> self: (x: Int)Int
      def square(x: Int): Int = x * x                 //> square: (x: Int)Int
      def powerOfTwo(x: Int): Int = if (x == 0) 1 else 2 * powerOfTwo(x - 1)
                                                      //> powerOfTwo: (x: Int)Int
    
      def sumInts(a: Int, b: Int): Int = sum(self, a, b)
                                                      //> sumInts: (a: Int, b: Int)Int
      def sumSquared(a: Int, b: Int): Int = sum(square, a, b)
                                                      //> sumSquared: (a: Int, b: Int)Int
      def sumPowersOfTwo(a: Int, b: Int): Int = sum(powerOfTwo, a, b)
                                                      //> sumPowersOfTwo: (a: Int, b: Int)Int
      println(sumInts(1, 5))                          //> 15
      println(sumSquared(1, 5))                       //> 55
      println(sumPowersOfTwo(1, 5))                   //> 62
    
    示例说明:
    • sumInts函数:求连续整数的和
    • sumSquared函数:求连续整数的平方和
    • sumPowersOfTwo函数:求连续整数的关于2的幂次和

    占位符语法

    使用下划线作为一个或多个参数的占位符,只要每个参数在函数字面量内仅出现一次。
      println("Testing, Scala!")                      //> Testing, Scala!
      val numList = List(-3, -5, 1, 6, 9)             //> numList  : List[Int] = List(-3, -5, 1, 6, 9)
      numList.filter(x => x > 0)                      //> res0: List[Int] = List(1, 6, 9)
      numList.filter(_ > 0)                           //> res1: List[Int] = List(1, 6, 9)
    
    示例说明:
    当采用下划线的表示方法时,对于列表numList中的每个元素,都会依次传入用来替换下划线。
    比如,首先传入-3,判断-3>0是否成立,是则把该值放入结果集合,否则舍弃;然后传入-5,判断-5>0是否成立,依此类推。

    柯里化

    柯里化函数(Curried Funciton)把具有多个参数的函数转化为一条函数链,每个节点上是单一参数。
    在函数式编程中,可以基于一些通用性的函数,利用柯里化函数等来构造新函数,而不需要重新定义新函数。
    示例:
      def add(x: Int, y: Int) = x + y                 //> add: (x: Int, y: Int)Int
      add(1, 2)                                       //> res0: Int = 3
    
      def addCurried(x: Int)(y: Int) = x + y          //> addCurried: (x: Int)(y: Int)Int
      addCurried(1)(2)                                //> res1: Int = 3
    
      val addOne = addCurried(1)_                     //> addOne  : Int => Int = TestScala$$$Lambda$8/6738746@7cf10a6f
      addOne(2)                                       //> res2: Int = 3
    
    示例说明:
    函数add和addCurried的函数定义时等价的。
    “addCurried(1)_”的下划线是通配后面所有的参数列表。

    递归

    在函数式编程中利用递归函数(Recursive Funtion)实现循环。
      def factorial(n: Int): Int =
        if (n <= 0) 1
        else n * factorial(n - 1)                     //> factorial: (n: Int)Int
      factorial(5)                                    //> res0: Int = 120
    

    尾递归

    在尾递归函数(Tail Recursive Funtion)中所有递归形式的调用都出现在函数的末尾。
    当编译器检测到一个函数调用时尾递归的时候,它就覆盖当前的活动记录,而不是在栈中去创建一个新的。
    Scala编译器不会主动进行尾递归优化,需要“@annotation.tailrec”来 告知Scala编译器
    package testscala
    
    object TestScala {
      def main(args: Array[String]) {
        println("Testing, Scala!")
        val res = factorial2(5, 1)
        println(res)
      }
    
      @annotation.tailrec
      def factorial2(n: Int, m: Int): Int =
        if (n <= 0) m
        else factorial2(n - 1, m * n)
    
    }
    

    示例:求整数a到b的相加之和

      def sum(f: Int => Int)(a: Int)(b: Int): Int = {
    
        @annotation.tailrec
        def loop(n: Int)(acc: Int): Int = {
          if (n > b) {
            println(s"n=${n},acc=${acc}")
            acc
          } else {
            println(s"n=${n},acc=${acc}")
            loop(n + 1)(acc + f(n))
          }
        }
    
        loop(a)(0)
      }                                               //> sum: (f: Int => Int)(a: Int)(b: Int)Int
    
      sum(x => x)(1)(5)                               //> n=1,acc=0
                                                      //| n=2,acc=1
                                                      //| n=3,acc=3
                                                      //| n=4,acc=6
                                                      //| n=5,acc=10
                                                      //| n=6,acc=15
                                                      //| res0: Int = 15
      sum(x => x * x)(1)(5)                           //> n=1,acc=0
                                                      //| n=2,acc=1
                                                      //| n=3,acc=5
                                                      //| n=4,acc=14
                                                      //| n=5,acc=30
                                                      //| n=6,acc=55
                                                      //| res1: Int = 55
      sum(x => x * x * x)(1)(5)                       //> n=1,acc=0
                                                      //| n=2,acc=1
                                                      //| n=3,acc=9
                                                      //| n=4,acc=36
                                                      //| n=5,acc=100
                                                      //| n=6,acc=225
                                                      //| res2: Int = 225
    
      val square = sum(x => x * x)_                   //> square  : Int => (Int => Int) = TestScala$$$Lambda$13/757108857@6bdf28bb
      square(1)(5)                                    //> n=1,acc=0
                                                      //| n=2,acc=1
                                                      //| n=3,acc=5
                                                      //| n=4,acc=14
                                                      //| n=5,acc=30
                                                      //| n=6,acc=55
                                                      //| res3: Int = 55
    
  • 相关阅读:
    两个数组的交集 II
    存在重复
    旋转数组
    从排序数组中删除重复项
    ps 修补工具
    最长公共前缀
    meta 属性
    19年面试总结
    java文件下载以及中文乱码解决
    关于web开发中,图片加载失败替换为默认图片
  • 原文地址:https://www.cnblogs.com/anliven/p/10041890.html
Copyright © 2020-2023  润新知