Scala函数式编程

函数式编程

面向对象编程OOP

解决问题

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

对象:用户

行为:登录、JDBC、读取数据库

属性:用户名、密码

Scala语言是一个完全面向对象编程语言

对象的本质:对数据和行为的一个封装

函数式编程

函数式编程是种编程方式,它将电脑运算视为函数的计算。函数编程语言最重要的基础是λ演算(lambda calculus),而且λ演算的函数可以接受函数当作输入(参数)和输出(返回值)。 [1]

和指令式编程相比,函数式编程强调函数的计算比指令的执行重要。

和过程化编程相比,函数式编程里函数的计算可随时调用。

函数基础

函数基本用法
def sum(x: Int, y: Int): Int = {
    x + y
}
函数和方法的区别

为完成某一功能的程序语句的集合,成为函数

类中的函数称之为方法

函数定义
  • 无参,无返回值
  • 无参,有返回值
  • 有参,无返回值
  • 有参,有返回值
  • 多参,无返回值
  • 多参,有返回值
package chapter05

object Test02_FunctionDefine {
  def main(args: Array[String]): Unit = {
    // 无参,无返回值
    def f1(): Unit = {
      println("无参,无返回值")
    }
    f1()
    println(f1())
    println("-----------------------")

    // 无参,有返回值
    def f2(): String = {
      println("无参,有返回值")
      return "This is f2 return value."
    }
    // f2()
    println(f2())
    println("-----------------------")

    // 有参,无返回值
    def f3(name: String): Unit = {
      println("有参,无返回值" + name)
    }
    println(f3("zihoo"))
    println("-----------------------")

    // 有参,有返回值
    def f4(name: String): String = {
      println("有参,有返回值" + name)
      return "This is f4 return value"
    }
    println(f4("zihoo"))
    println("-----------------------")

    // 多参,无返回值
    def f5(name1: String, name2: String): Unit = {
      println("多参,无返回值")
      println(name1 + "和" + name2 + "打招呼")
    }
    println(f5("zihoo", "gazikel"))
    println("-----------------------")

    // 多参,有返回值
    def f6(a: Int, b: Int): Int = {
      println("多参,有返回值")
      return a + b
    }
  }
}
函数参数
  • 可变参数
  • 如果参数列表存在多个参数,那么可变参数一般放置在最后
  • 参数默认值,一般将有默认值的参数防止在参数列表的后面
  • 带名参数,带着参数名称传值,传值就可以与顺序无关
package chapter05

object Test03_FunctionParameter {
  def main(args: Array[String]): Unit = {
    // 可变参数
    def f1(str: String*): Unit = {
      println(str)
    }
    f1("zihoo")
    f1("zihoo", "gazikel")
    println("----------------------")

    // 如果参数列表中存在多个参数,那么可变参数放在最后
    def f2(number: Int, str: String*): Unit = {
      println("number:" + number + ", str:" + str)
    }
    f2(10)
    println("----------------------")

    // 参数默认值,一般将有默认值的参数放置在参数列表的后面
    def f3(name: String = "school"): Unit = {
      println("I am at " + name)
    }
    f3()
    f3("home")
    println("----------------------")

    // 带名参数
    def f4(name: String, age: Int):Unit = {
      println(s"${name}${age}岁了")
    }
    f4("zihoo", 21)
    f4(age = 21, name = "zihoo")
  }
}
函数至简原则

能省则省

package chapter05

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

    def f0(name: String): String = {
      return name
    }

    // return可以省略,Scala会使用函数体的最后一行代码作为返回值
    def f1(name: String): String = {
      name
    }

    // 如果函数体只有一行代码,可以省略花括号
    def f2(name: String): String = name
    // 返回值类型如果能够推断出来,那么可以省略
    def f3(name: String) = name

    // 如果有return,则不能省略返回值类型,必须指定
    // 如果函数明确声明unit,那么即使函数体中使用return关键字也不起作用
    def f5(name:String):Unit = {
      return "这个return不起作用"
    }
    println(f5("zihoo"))

    // Scala如果期望是无返回值类型,可以省略等号
    def f6(name: String) {
      println("可以省略等号")
    }

    // 如果函数无参,但是声明了参数列表,那么调用时,小括号可加可不加
    def f7() = {
      println("f7")
    }
    f7()
    f7

    // 如果函数没有参数列表,那么小括号可以省略,调用时小括号必须省略
    def f8 {
      println("f8")
    }
    f8

    // 如果不关心名称,只关心逻辑处理,那么可以将函数名省略
    // 匿名函数,lambda表达式
    (name: String) => { println(name) }
  }
}

那么匿名函数连名字都没有,怎么调用呢?

下面,详细讲述一下lambda表达式的使用。

函数高级

高阶函数

函数可以作为值进行传递

package chapter05

object Test06_HighOrderFunction {
  def main(args: Array[String]): Unit = {
    def f(n: Int): Int = {
      println("f调用")
      n + 1
    }

    val result = f(123)
    println(result)

    // 函数作为值进行传递
    val f1: Int => Int = f
    val f2 = f _
    println(f1) // chapter05.Test06_HighOrderFunction$$$Lambda$5/1908923184@4563e9ab
    println(f1(23))
    println(f2) // chapter05.Test06_HighOrderFunction$$$Lambda$6/431687835@11531931
    println(f2(35))
  }
}

函数可以作为参数进行传递

package chapter05

object Test06_HighOrderFunction {
  def main(args: Array[String]): Unit = {
    // 函数作为参数进行传递
    // 定义二元计算函数
    def dualEval(op: (Int, Int) => Int, a: Int, b: Int): Int = {
      op(a, b)
    }

    def add(num1: Int, num2: Int): Int = {
      num1 + num2
    }

    println(dualEval(add, 1, 2))

    dualEval((a, b) => {
      a + b
    }, 10, 20)
  }
}

函数可以作为函数返回值返回

package chapter05

object Test06_HighOrderFunction {
  def main(args: Array[String]): Unit = {
    // 函数可以作为函数返回值返回
    def f5(): Int => Unit = {
      def f6(a: Int): Unit = {
        println("f6调用" + a)
      }
      // 将函数直接返回
      f6
    }

    println(f5()) // chapter05.Test06_HighOrderFunction$$$Lambda$9/1975358023@7d417077
    f5()(26)
  }
}

案例实操

对于集合的数据处理

package chapter05

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

    val arr: Array[Int] = Array(12, 45, 75, 98)

    // 对数据进行处理,将操作抽象出来,处理完毕的结果返回一个新的数组
    def arrayOperation(arr: Array[Int], op: Int=>Int): Array[Int] = {
      for(elem <- arr) yield op(elem)
    }

    // 定义一个+1操作
    def addOne(elem: Int): Int = {
      elem + 1
    }

    // 调用函数
    val newArray: Array[Int] = arrayOperation(arr, addOne)
    println(newArray.mkString(","))

    // 传入匿名函数
    val newArray2: Array[Int] = arrayOperation(arr, (elem) => elem * 2)
    println(newArray2.mkString(","))

  }
}
匿名函数

没有名字的函数

高阶函数案例
  1. 定义一个匿名函数,并将它作为值赋给变量fun。函数有三个参数,类型分别为Int, String, Char,返回值类型为Boolean

    要求调用函数fun(0, "", '0')得到返回值为false,其它情况均返回true

  2. 定义一个函数func,它接收一个Int类型的参数,返回一个函数(记作f1)。它返回的函数f1,接收一个String类型的参数,同样返回一个函数(记作f2)。行距是f2接收一个Char类型的参数,返回一个Boolean值。

    要求调用函数func(0)("")('0')得到返回值为false,其它情况均返回true

package chapter05

object Test08_Practice {
  def main(args: Array[String]): Unit = {
    // 练习1
    val fun = (i: Int, s: String, c: Char) => {
      if (i == 0 && s == "" && c =='0') {
        false
      } else {
        true
      }
    }

    println(fun(0, "", '0'))
    println(fun(1, "", '0'))

    def func(i: Int): String => Char => Boolean = {
      def f1(str: String): Char => Boolean = {
        def f2(c: Char): Boolean = {
          if (i == 0 && str == "" && c =='0') {
            false
          } else {
            true
          }
        }
        f2
      }
      f1
    }
  }
}
函数柯里化&闭包

闭包:如果一个函数,访问到了它的内部(局部)变量的值,那么这个函数和它所处的环境,称为闭包。

函数柯里化:把一个参数列表的多个参数,编程多个参数列表。

递归

一个函数(或方法)在函数(方法)体内又调用了本身,我们称之为递归调用。

package chapter05

object Test10_Recursion {
  def main(args: Array[String]): Unit = {
    println(fact(5))
  }

  // 递归实现计算阶乘
  def fact(n: Int): Int = {
    if(n==1)
      1
    else
      (n - 1) * n
  }
}
控制抽象

值调用:把计算后的值传递过去

package chapter05

object Test11_ControlAbstraction {
  def main(args: Array[String]): Unit = {
    // 传值参数
    def f0(a: Int): Unit = {
      println("a:" + a)
    }
    f0(23)

    def f1(): Int = {
      println("f1调用")
      12
    }
    f0(f1())
  }
}

名调用:把代码传递过去

package chapter05

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

    def f1(): Int = {
      println("f1调用")
      12
    }
    f0(f1())

    println("-------------")
    // 传名参数
    def f2(a: => Int): Unit = {
      println("a:" + a)
      println("a:" + a)
    }
    f2(f1())
    
    f2({
      println("这是一个代码块")
      29
    })
  }
}
惰性函数

函数返回值被声明为lazy时,函数的执行被推迟,直到我们首次对此取值,该函数才会执行。这种函数我们称之为惰性函数。

package chapter05

object Test13_Lazy {
  def main(args: Array[String]): Unit = {
    lazy val result: Int = sum(13, 47)

    println("1. 函数调用")
    println("2. result = " + result)

    def sum(a: Int, b: Int): Int = {
      println("3. sum调用")
      a + b
    }
  }
}
posted @ 2022-01-04 19:50  Gazikel  阅读(143)  评论(0编辑  收藏  举报