Scala函数高级篇

一、匿名函数

没有名字的函数就是匿名函数,格式:(x:Int)=>{函数体} 

x:表示输入参数类型;Int:表示输入参数类型;函数体:表示具体代码逻辑

传递匿名函数至简原则:

  1. 参数的类型可以省略,会根据形参进行自动的推导;
  2. 类型省略之后,发现只有一个参数,则圆括号可以省略;其他情况:没有参数和参数超过1的永远不能省略圆括号;
  3. 匿名函数如果只有一行,则大括号也可以省略 ;
  4. 如果参数只出现一次,则参数省略且后面参数可以用_代替;
object FunctionTest04 {
  def main(args: Array[String]): Unit = {
    //将匿名函数传给变量 fun
    var fun = (s: String) => {println(s)}

    //func: String=> Unit  表示传入一个参数为String类型,返回值为Unit类型的函数变量
    // f就是一个参数为函数类型,返回值为Unit的普通函数
    def f(func: String=> Unit): Unit = {
      //表示这个函数参数的默认值
      func("Hello,Scala")
    }
    //这两个意思完全相同
    f(fun)
    f((s: String) => {println(s)})

    //1、匿名函数简化:函数的参数只有一个或者没有,可以省略小括号
    //函数体只有一句可以省略大括号
    f(s => println(s))

    //2、匿名函数简化:当函数的参数只有一个且只出现一次时,该参数的名字可以是任意的名字
    //因此,也可以用通配符“_”来表示
    f(println(_))

    //3、匿名函数简化:如果可以推断出println是函数体,而不是调用的语句,可以直接省略"_"
    //注意:小括号必须要省略,否则会认为是调用语句
    f(println)
  }
}

多个参数的匿名函数应用:

//多参数的匿名函数
    def caculator(a: Int,b: Int,op: (Int,Int) => Int):Int = {
      op(a,b)
    }
    //1、标准版
    println(caculator(2,3,(x: Int,y: Int) => {x + y}))
    //2、省略花括号以及参数类型
    println(caculator(2,3,(x,y) => x + y))
    //3、由于x,y只出现了一次,故也可以简化
    println(caculator(2,3,_ + _))

二、高级函数应用

2.1 函数作为值进行传递

//函数的定义
    def fun3():Unit = {
      println("定义一个函数")
    }
    //调用函数
    fun3()

    //函数作为值传递
    //这相当于调用一次fun3函数
//    var v = fun3()
    var v = fun3

    //将函数传递给变量的标准形式
    var v1: ()=>Unit = fun3
    //简化形式, _代表fun3后面的函数体
    var v2 = fun3 _

2.2 函数作为参数传递

//定义一个加法函数
    def add(a: Int,b: Int): Int = a + b
    //这个函数的参数是函数签名(by-name),f表示函数名称,(Int,Int)表示函数的输入类型
    //箭头后的Int表示返回类型
    //这种方式相当于只传入行为
    //函数体中定义了数据
    def caculators(f: (Int,Int) => Int):Int = {
      f(2,4)
    }
    //将add作为参数传递给caculators
    //如果能推断出不是调用,也可以把 _省略
    println(caculators(add _))
    println(caculators(add))

2.3 函数作为函数返回值返回

//函数作为返回值返回
    def f1() = {
      def f2 = {
        println("我是f2")
      }
      //这是f1的返回
      f2 _
    }
    //因为调用f1的返回值是个函数f2,所以变量v3可以继续调用
    var v3 = f1()
    v3()
    //以上两部可以简化为
    f1()()

三、阶段练习

object FunctionTest05 {
  def main(args: Array[String]): Unit = {
    /*
    * 练习1:定义一个匿名函数,并将它作为值赋给变量fun。函数有三个参数,类型分别为Int,String,Char,返回值类型为Boolean。
    * 要求调用函数fun(0, “”, ‘0’)得到返回值为false,其它情况均返回true。
    * */
    var fun = (i: Int,s: String,c: Char) =>{
      if (i == 0 && s == "" && c == '0')
        {
          println("false")
          return false
        }else{
        println("true")
        return true
      }
    }
    fun(0,"",'0')
    /*
    * 练习2: 定义一个函数func,它接收一个Int类型的参数,返回一个函数(记作f1)。
    * 它返回的函数f1,接收一个String类型的参数,同样返回一个函数(记作f2)。
    * 函数f2接收一个Char类型的参数,返回一个Boolean的值。
    * 要求调用函数func(0) (“”) (‘0’)得到返回值为false,其它情况均返回true。
    * */
    def func (i:Int) = {
      def f1(s: String) = {
        def f2(c: Char): Boolean = {
          if (i == 0 && s == "" && c == '0')
          {
            println("false")
            return false
          }else{
            println("true")
            return true
          }
        }
        //返回函数 f2
        f2 _
      }
      //返回函数f1
      f1 _
    }
    func(0)("")('0')
  }
}

 

/*
    * 模拟Map映射、Filter过滤、Reduce聚合
    * */
    //1、模拟Map映射
    //array 代表传入数据
    //op 代表传入的操作函数
    def Map(array: Array[Int], op: Int => Int): Array[Int] = {
      // 遍历数组并将返回值elem传递给函数 op
      for (elem <- array) yield op(elem)
    }

    //定义数组
    var arr: Array[Int] = Array(10,20,30,40)
    //定义操作:数据加1
    def addOne(i: Int):Int = i+1

    //调用Map函数
    // Map(arr,addOne) 返回的是一个引用类型,需要使用mkString方法
    println(Map(arr,addOne).mkString(","))
  }

输出:11,21,31,41
//接上面代码,简化操作
//例如:所有元素乘2
var arr2 = Map(Array(10,20,30,40),_ * 2)
println(arr2.mkString(","))
输出:20,40,60,80
def main(args: Array[String]): Unit = {
    //2、模拟Filter过滤
    def Filter(array: Array[Int], op:Int => Boolean) = {
      //需要导入ArrayBuffer类
      var arr: ArrayBuffer[Int] = new ArrayBuffer[Int]()
      //循环判断
      for (elem <- array if op(elem)){
        arr.append(elem)
      }
      arr.toArray
    }
    //排除数组中的偶数
    var arr1 = Filter(Array(1,2,3,4,5,6), _ % 2 == 1)
    //打印输出
    println(arr1.mkString(","))
  }
def main(args: Array[String]): Unit = {
    //3、模拟Reduce聚合操作
    def Reduce(array: Array[Int],op: (Int,Int) => Int) = {
      //获取输入的数组的第一个值
      var init: Int = array(0)
      //循环遍历数组,左闭又开区间
      for (elem <- 1 until array.length ){
        //执行对应的操作
        init = op(init,array(elem))
      }
      //返回 Init
      init
    }
    //输入数组以及累加操作
    println(Reduce(Array(1,2,3,4),_ + _))

  }

四、函数柯里化&闭包

闭包:函数式编程的标配 ,如果一个函数,访问到了它的外部变量的值,那么这个函数和他所处的环境,称为闭包 ;

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

def main(args: Array[String]): Unit = {
    /*
    * 函数闭包&柯里化
    * */
    //1、闭包代码示例
    def f1()={
      var v:Int = 3;
      //函数f2用到了函数外的变量v,此时f2就是一个闭包的环境
      def f2(a: Int) = {
        v + a
      }
    }

    //2、柯里化示例
    def add(a: Int,b: Int) = {
      a + b
    }
    //变为如下形式,就是柯里化
    def addCur(a: Int)(b: Int) = a + b
    //具体实现过程是,先演变为:
    //实际就是函数add1中嵌套了一个匿名函数: (b: Int) => a + b
    def add1 (a: Int) = (b: Int) => a + b

  }

 五、递归

注意:在Scala的递归中,必须声明函数返回值类型

 def main(args: Array[String]): Unit = {
    test(5)
  }
  def test(i: Int):Int = {
    if (i == 1) return 1
      else {
      i * test(i - 1)
    }
  }

六、控制抽象

Scala的解释器在解析函数参数(function arguments)时有两种方式:

  1. 传值调用:先计算参数表达式的值,再应用到函数内部;
  2. 传名调用:将未计算的参数表达式直接应用到函数内部。

注意:Java只有值调用;Scala既有值调用,又有名调用。 

def main(args: Array[String]): Unit = {
    //传名调用示例:
    delayed(time())
  }
  def time() = {
    println("时间:")
    System.nanoTime()
  }
  def delayed(t: => Long) = {
    println("参数:" + t)
  }

七、惰性加载

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

def main(args: Array[String]): Unit = {
    //注意:这里只能声明为常量val
    lazy val v = sum(2,3)
    println("----------------------")
    println("v=" + v)
  }
  def sum(a: Int,b: Int) = {
    println("sum 被执行了")
    a + b
  }

输出:
----------------------
sum 被执行了
v=5

 

你可能感兴趣的:(Scala函数高级篇)