函数进阶

43 阅读5分钟

(一) 函数的字面量语法

1.除了使用def之外的,另一种定义函数的方式

语法: var 变量 = (参数列表)=>{方法体}

它省略了def,函数名以及函数的返回值类型。

// 定义  
val sum1 = (x:Int, y:Int)=>{x+y}  
// 调用  
var s = sum1(10,34)
object base43 {
  /**
   * 函数字面量
   * 另一种定义函数的方式
   */

  // 定义函数的方式一:def
  def getSum(x: Int, y: Int): Int = {
    x + y
   }

  // 定义函数的方式二:字面量
  val getSum1 = (x: Int, y: Int) => {
    x + y
  }

  
  def main(args: Array[String]): Unit = {
    println(getSum(10, 20))
    println(getSum1(10, 20))
  }

}

image.png

2.Scala的函数字面量的简化方式有两种方式:

第一种方式为: _(占位符)。如果函数中的参数在方法体中只使用了一次,可以用_替换。

第二种方式为: 只有一个表达式时,可以省略括号。

val sum1 = (x:Int, y:Int) =>{x+y}  
val sum2 = (x:Int, y:Int) => x+y  
val sum3:(Int, Int)=>Int = _ + _  
val sum4 = (_: Int) + (_: Int)

函数字面量的简化写法:

object base44 {
  /*
    * 函数字面量的简化写法
    * 1. 代码只有一句,省略 {}
    * 2. _ 占位符来替换形参
  */
  //
  val getSum = (x: Int, y: Int) => {
    x + y
  }

  // 省略 {}
  val getSum1 = (x: Int, y: Int) => x + y

  // 使用 _ 来代替形参
  val getSum2 = (_: Int) + (_: Int)

  //使用 _ 来代替形参,(Int,Int) => Int 就是getSum3的类型
  val getSum3 :(Int,Int) => Int =_+_

  def main(args: Array[String]): Unit = {
    println(getSum(10, 20))
    println(getSum1(10, 20))
    println(getSum2(10, 20))
    println(getSum3(10, 20))
  }

}

image.png

(二)把函数作为参数

某个函数的参数是函数

定义一个接收函数作为参数的函数

def a(f:()=>Unit)={},其中函数的类型()=>Unit部分()为函数的参数,Unit为函数的返回值。

通过定义字面量传递值时,字面量必须和函数的类型匹配。

把一个函数 当做参数 传递给另一个函数

eg:1

object base45 {
  /**
   * 把一个函数 当做参数 传递给另一个函数
   */

  // 定义两个字面量函数,(Int, Int) => Int 看成一种数据类型
  val f1: (Int, Int) => Int = _ + _
  // val a:Int = 1

  val f2: (Int, Int) => Int = _ * _

  // 定义一个函数,它有三个参数
  // 参数1:类型是(Int,Int)=>Int 。它表示这里需要一个函数
  def test(fn: (Int, Int) => Int, x: Int, y: Int): Int = {
    fn(x, y)
  }

  def main(args: Array[String]): Unit = {
    println(test(f1, 10, 20) )
    println(test(f2, 10, 20))
  }
}

image.png eg:2

// 奶茶店1  
    var add = (x:Int, y:Int) => x + y  
    // 咖啡店1  
    var mul = (x:Int, y:Int) => x*y  
    // 定义一个函数。它的特点是:第一个参数的类型是函数!  
    // 美团  
    var op = (fn: (Int, Int)=>Int, a:Int, b:Int) => {  
      fn(a,b)  
    }  
    //    add(100, 200) // 直接去奶茶店买  
  
    println( op(add, 100, 200) )  
    println( op(mul, 100, 200) )

说明:add理解为直接去奶茶店购买

(三)把函数作为返回值

函数的返回值是一个函数。

def main(args: Array[String]): Unit = {  
    // 函数f 的返回值就是一个函数  
    var f = (x:Int) => {  
      // println(x)  
      //      var f1 = (y:Int) => x + y  
      //      f1 // 返回值是一个函数  
      (y:Int) => x + y  
    }  
  
    var s = f(2) //  s 是一个函数  
    var res = s(10)  
    println(res)  
  }

(四)Scala的函数的闭包

1.什么是闭包

闭包是:一个函数连同该函数的非局部变量的一个引用环境。

函数和变量的定义要在同一个作用域,函数可以引用已经创建的变量,函数可以同值一样被传递和应用,当执行函数时该函数仍然引用着变量。

def makeAdder(adder: Int): Int => Int = {

     (x: Int) => x + adder

  }

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

    val addFive = makeAdder(5)

    val addTen = makeAdder(10)

    println(addFive(3))  // 输出 8

    println(addTen(3))   // 输出 13

  }

}

(五)函数的柯里化格式定义

定义函数的另一种格式。

柯里化的定义语法为:

def 函数名(参数列表1)(参数列表2)...(参数列表n):type={

方法体

}

柯里化是什么?

柯里化(Currying)是函数式编程中的一个非常重要的概念,得名于美国数学家 Haskell Curry。柯里化的基本思想是将一个接受多个参数的函数转变为一系列只接受一个参数的函数,并返回接受下一个参数的新函数。

// 正常定义  
def add(x:Int,y:Int)=x+y  
println(add(1,2))  
// 柯里化定义:一个参数一个括号,参数单独写

def add(x:Int)(y:Int) = x + y  
println(add(1)(2))

(六)Scala部分应用函数

如果一个函数包含多个参数,对该函数传递部分参数使得这个函数返回一个函数,那么这种函数叫做部分应用函数。

// 定义普通函数  
def mutlti(x:Int, y:Int, z:Int) = {  
  println(s"$x, $y, $z")  
  x * y * z  
}  
// 传入部分参数,返回部分函数  
var f1 = mutlti(2, _, _)  
// 调用部分函数  
println( f1(10, 5) )

部分应用函数

object base46 {
  /**
   * 部分应用函数
   * 如果一个函数需要3个参数,而我们只给了2个参数,会怎么样?
   */

  def getSum(a: Int, b: Int, c: Int): Int = {
    a + b + c
  }

  def main(args: Array[String]): Unit = {
    println(getSum(10, 20, 30))
    val t = getSum(10, 20, _) // t 就是部分应用函数!
    val t1 = getSum(_, 20, _) // t1 就是部分应用函数!

    println(t(30))
    println(t1(20, 50))
  }
}

image.png