【Scala 2.11.8 入门 】Scala入门②函数式编程 2019_12_3

函数式编程

函数基础

一切皆函数(真),一切皆对象(真)
【PS:而不像Java 还有为了舔C++遗留的基本数据类型】

//基础语法:
def    sum (x: Int , y: Int) : Int           =   { x + y }
关键字 函数签名                 函数返回值类型       函数体

//函数 || 方法:
定义在 class 类体中的 函数 称为 方法【当然二者结构都可是一样的】{
定义在 方法 中的 函数 称为 函数
注1:Scala语言可以在任何的语法结构中声明任何的语法
注2:函数没有重载和重写的概念;方法可以进行重载和重写
注3:Scala中函数可以嵌套定义
函数嵌套
object TestFunction {
    def main(args: Array[String]): Unit = {
        //嵌套 定义函数
        def test1() ={
            def test2(name:String):Unit={
                println("函数可以嵌套定义")
            }
            test2("abc")
        }
        test1() // 函数可以嵌套定义
    }
}
函数参数
函数参数:
(1)可变参数
(2)如果参数列表中存在多个参数,那么可变参数放置在最后
(3)参数默认值,一般将有默认值的参数放置在参数列表的后面
(4)带名参数,如果有默认值参数不在参数列表的最后,可以在调用函数的时候使用 命名参数

//1.可变参数 Type*
def test( s : String* ): Unit = {
    println(s)
}

//2.多参数,可变参数放置最后
def test2( id: Int, s: String* ): Unit = {
    println(s)
}

//3.参数默认值
def test3( name : String, age : Int = 30 ): Unit = {
    println(s"$name, $age")
}
def test4( age : Int = 30, name : String ): Unit = {
    println(s"$name, $age")
}

//(4)带名参数
test4(name="ximenqing") //ximengqing,30
函数至简原则
(1)return 可以省略,Scala会使用函数体的最后一行代码作为返回值
(2){} 花括号可以省略,如果函数体只有一行代码,
(3): Type 参数类型/函数返回值类型 如果能够推断出来那么可以省略
(4)= 等号可以省略,如果函数期望是无返回值 Unit类型,
(5)() 小括号可以省略,如果函数没有显式声明参数列表(),那么调用时小括号必须省略
(6)def + 函数名 可以省略,如果不关心名称,只关心函数内部的逻辑处理
(7)如果函数无参,但是声明了参数列表,那么调用时,小括号,可加可不加
(8)如果函数体有return关键字,则不能省略声明函数返回值类型,必须指定
(9)如果函数返回值显式声明 Unit类型,那么即使函数体中使用return关键字也不起作用

函数高级

关于,Scala 函数Function 与方法Method 的区别:
如果定义在类体中,使用def 关键字,我们通常叫它为 方法
如果定义在方法中,通常不使用 def 关键字,我们通常加它为 函数

高阶函数
函数作为值传递 val a = foo()
函数作为整体传递 val b = foo _
函数作为参数传递 (f: U => V)
函数作为函数返回值 { f2_ }

一切皆函数
object TestFuncHigh {
  def main(args:Array[String]): Unit ={
    //1.将函数返回值 传递给 var/val
    println("--- 函数返回值被传递 ---")
    val fv = fValue(1) // 简写==> val fv = fValue()
    println(fv)

    //2.1将函数整体 传递给 var/val _代表参数/返回值类型推断
    println("--- 函数整体被传递 ---")
    val ff = fValue _
    println(ff(2))

    //2.2明确var/val 函数参数&返回值类型,则可以不使用 _
    var ff2:(Int)=>Int = fValue
    println(ff2(3))

    //3.将嵌套定义的内层 函数整体 作为外层 函数返回值 传递给变量(函数整体传递的一种)
    println("--- 内层函数整体作为外层函数返回值被传递 ---")
    println("单层调用")
    val innerF = f1()
    println("单层调用")
    innerF()
    println("双层调用")
    f1()()

    //4.函数作为形式参数被定义 及 传递调用
    println("--- 函数作为形式参数被定义及传递调用 ---")
    val fP = fParam(fValue)
    println(fP)

  }

  def fValue(a: Int): Int ={
    println("fValue")
    a
  }

  def f1 ()={
    println("f1")
    def f2 ()={
      println("f2")
    }
    f2 _
  }
    
  def m1(a:Int) = {
    def m2(b:Int)= {
      def m3(m4:(Int,Int)=>Int)= {
        m4(a,b)
      }
      m3 _
    }
    m2 _
  }

  //完整函数定义:def 函数签名 : 函数返回值 = {函数体}
  //函数作为形式参数声明:参数列表 (形参函数名: 参数1,参数2,... => 形参函数返回值类型)
  //注:形参函数写在 参数列表 == 小括号()里,也就没办法写完整函数定义,一切从简
  def fParam(f: Int => Int): Int = {
    //调用传入参数:函数f
    f(4)
  }
}
匿名函数
匿名函数 == 不关心函数名称 / 不二次调用的函数。如 形参函数
格式:(参数列表)=>{函数体}
传递匿名函数简化原则:
(1)参数类型 :Type 省略,会根据形参进行自动的推导
(2)只有一个参数,则圆括号 () 可以省略;其他情况:没有参数和参数超过1的永远不能省略圆括号。
(3)函数体只有一行,则大括号 {} 也可以省略
(4)参数只出现一次,则参数省略且后面参数调用可用"_"代替

object TestAnonymity {
  def main(args: Array[String]): Unit = {
    //0.传入 实参 函数f1
    val arr0 = f0(Array(1, 2, 3, 4), f1)
    println(arr0.mkString(","))

    //1.传入 一个实参 匿名函数
    val arr1 = f0(Array(1, 2, 3, 4), _ + 1)
    println(arr1.mkString(","))

    /**
     * val arr1 = f0(Array(1,2,3,4),(ele:Int)=>{ele+1})
     * val arr2 = f0(Array(1,2,3,4),(ele)=>{ele+1})
     * val arr3 = f0(Array(1,2,3,4),ele=>{ele+1})
     * val arr4 = f0(Array(1,2,3,4),ele=>ele+1)
     * val arr5 = f0(Array(1,2,3,4),_+1)
     */

    //2.传入 两个实参 匿名函数
    val arr2 = f2(Array(1, 2, 3, 4), _ + _)
    println(arr2.mkString(","))
  }

  def f0(arr: Array[Int], op: Int => Int) = {
    for (elem <- arr) yield op(elem)
  }

  def f2(arr: Array[Int], op: (Int, Int) => Int) = {
    for (elem <- arr) yield op(elem, 1)
  }

  def f1(m1: Int): Int = {
    m1 + 1
  }
}
闭包&函数柯里化
闭包 == {外部函数的局部变量(外部函数已弹栈的情况下)存活 + 内部函数} ==> 新的对象 == 同一生命周期
函数柯里化 == 一个参数列表 转换为 多个参数列表 && 嵌套函数(闭包)的声明简化(可配合代码块传递)

object TestBBFunction {
  def main(args: Array[String]): Unit = {
    var a = 10

    //非函数式嵌套调用:
    //特点:在最内层调用未完成时,外层调用的方法并不弹栈
    //     以达到外层局部变量共享给内部调用函数,当外部调用的方法弹栈后,其局部变量也弹栈/释放
    TraditionM1(a)

    //函数式嵌套调用
    //特点:外层方法执行完毕后,方法出栈,而其仍被内层函数使用的局部变量不弹栈
    //     与内层函数组成一个共生命周期的环境/共同体/新对象【形成=>官方·闭包】
    val b = f1(a)()
    //多次执行,只执行()()()第三层嵌套函数,其所需的第一层方法的局部变量仍然留存。
    b() //10
    b() //10

    //柯里化,简化闭包函数(嵌套函数)调用
    klh(1)("abc")
  }

  /**
   * 传统方法的链式调用,缺点:大量嵌套方法压栈,栈空间不足
   * 优点:层次分明,易于理解
   * @param b 共享给m2,m3的参数
   */
  def TraditionM1(b: Int): Unit = {
    m2(b)
  }

  def m2(c: Int): Unit = {
    m3(c)
  }

  def m3(d: Int): Unit = {
    println(d)
  }

  /**
   * 1.嵌套的内部方法,可共享可能已被方法栈弹出的外部方法的局部变量 ==> 闭包
   * 2.定义完f2,f3,需要将这些方法作为方法返回值返回
   * 3.方法的嵌套调用,优点:执行完的方法直接弹栈,但其嵌套范围内仍被引用的局部变量不会弹栈,
   *   也就是:解决了栈空间被嵌套方法占用问题,且弹栈方法的局部变量的生命周期被延长同内部嵌套函数
   *   也就是:嵌套外层的局部变量与其内部嵌套函数形成一个闭合共存空间 = 对象
   * @param b
   */
  def f1(b: Int)= {
    def f2()= {
      def f3()= {
        println(b)
      }
      f3 _
    }
    f2 _
  }

  /**
   * 柯里化简化多层方法嵌套
   * 注:这样写,会将第一层方法逻辑省略,但仍可通过——传递代码块的方式
   *    在最内层方法中加入外层函数逻辑
   *    
   * def myWhile(condition: => Boolean)(op: => Unit): Unit = {
   *   //1.如果满足循环条件,执行循环体op
   *   if (condition) {
   *     op
   *     myWhile(condition)(op)
   *   }
   * }
   *
   * @param a 第一层方法
   * @param s 第二层方法
   */
  def klh(a:Int)(s:String): Unit ={
    println(a)
  }
}
控制抽象
函数参数传递:3种情况
1.值传递
2.函数传递
3.代码块传递 ==> 控制抽象

object TestWhileFunction {
  def main(args: Array[String]): Unit = {
    //0.定义一个匿名函数,作为参数化函数
    val block = (res: Int) => {
      println("--- block ---")
      res
    }
    //1.传递值(block函数返回值)
    foo(block(10))
    /*
      --- block ---
      10
      10
     */

    //2.传递代码块
    foo2(block(10))
    /*
      --- block ---
      10
      --- block ---
      10
     */

    //3.传递函数
    foo3(block)

    //4.控制抽象实例:myWhile 函数,传入两个参数
    var i = 1
    myWhile(i <= 10) {
      println(i)
      i += 1
    }
  }

  //传递值
  //格式:(参数名: 参数类型)
  def foo(a: Int): Unit = {
    println(a)
    println(a)
  }

  //传递代码块
  //格式:(参数化代码块名: => 代码块返回值类型)
  def foo2(a: => Int) {
    println(a)
    println(a)
  }

  //传递函数
  //格式:(参数化函数名: 参数化函数参数类型 => 参数化函数返回值类型)
  def foo3(f: Int => Int): Unit = {
    println(f(10))
    println(f(10))
  }

  /**
   * 注意:condition 不能为变量参数(值传递),而应是代码块参数(可动态变化)
   *
   * @param condition 条件代码块
   * @param op        执行代码块
   */
  def myWhile(condition: => Boolean)(op: => Unit) {
    //1.如果满足循环条件,执行循环体op
    if (condition) {
      op
      myWhile(condition)(op)
    }
  }
}
递归
object TestDGFunction {
  def main(args: Array[String]): Unit = {
    println(jc(5))
    println(addFunction(20, 2))
  }

  /**
   * 阶乘方法
   * @param n n的阶乘
   * @return 递归式
   */
  def jc(n:Int):Int={
    //1.收敛条件:注意使用return结束整个函数
    if( n == 1)
      return 1
    //2.处理
    //3.return 递归
    n*jc(n-1)
  }
    
  /**
   * 位运算,实现的加法器
   * @param a 加数1 / 无进位和数
   * @param b 加数2 / 进位
   * @return 迭代式
   */
  def addFunction(a:Int,b:Int): Int ={
    if (b==0)
      return a
    addFunction(a^b,(a&b)<<1)
  }
}
惰性执行
object TestLazyFunction {
  def main(args: Array[String]): Unit = {
    //惰性关键字:只被允许定义在 val 不变量前
    //当函数返回值被声明为lazy时,函数的执行将被推迟,直到我们首次对此取值,该函数才会执行
    lazy val res = sum(10,10)
    println("_______")
    println("res="+res)
  }

  def sum (n1:Int,n2:Int):Int = {
    println("--sum--")
    n1 + n2
  }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值