函数进阶

74 阅读3分钟

1. 函数字面量

在 Scala 中,函数字面量(Function Literal)和部分应用函数(Partially Applied Function)是函数式编程的重要概念

(一)函数的字面量语法

[讲]除了使用def之外的,另一种定义函数的方式

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

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

核心特点

- 匿名性:没有函数名,可直接使用或赋值给变量

- 可作为值传递:能作为参数传入其他函数,或作为返回值

// 定义  
val sum1 = (x:Int, y:Int)=>{x+y}  
// 调用  
var s = sum1(10,34)

[简化写法]

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

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

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

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

(二)函数作为参数

[讲] 某个函数的参数是函数

[码] 定义一个接收函数作为参数的函数def a(f:()=>Unit)={},其中函数的类型()=>Unit部分()为函数的参数,Unit为函数的返回值。通过定义字面量传递值时,字面量必须和函数的类型匹配。

// 奶茶店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) )

(三)把函数作为返回值

函数的返回值是一个函数 代码:

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的函数的闭包

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

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

代码:

object ClosureExample2 {  
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={

方法体

}

代码:

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

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

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) )

核心特点

- 基于已有函数,固定部分参数,保留剩余参数的输入能力

- 语法上用下划线 (_) 表示未传入的参数

案例:

// 定义一个需要3个参数的函数
def calculate(a: Int, b: Int, c: Int): Int = a + b * c

// 1. 部分应用:只传入第一个参数,保留后两个参数
val partial1: (Int, Int) => Int = calculate(10, _, _)  // 固定a=10,需传入b和c
println(partial1(2, 3))  // 等价于calculate(10,2,3),输出:10 + 2*3 = 16

// 2. 部分应用:传入前两个参数,保留最后一个参数
val partial2: Int => Int = calculate(5, 2, _)  // 固定a=5, b=2,需传入c
println(partial2(4))  // 等价于calculate(5,2,4),输出:5 + 2*4 = 13

// 3. 部分应用:不传入任何参数(保留所有参数)
val partial3: (Int, Int, Int) => Int = calculate(_, _, _)  // 等价于原函数
println(partial3(1, 2, 3))  // 输出:1 + 2*3 = 7

// 4. 在高阶函数中使用部分应用
def log(time: String, message: String): Unit = {
  println(s"[$time] $message")
}

val todayLog: String => Unit = log("2025-10-20", _)  // 固定time,保留message
todayLog("系统启动")  // 输出:[2025-10-20] 系统启动
todayLog("任务完成")  // 输出:[2025-10-20] 任务完成