😎Scala: 函数进阶

78 阅读5分钟

一. 函数的字面量语法

前要

在 Scala 中,def 和函数字面量是定义 “可执行逻辑” 的两种核心方式,但本质上分别对应方法(Method)  和函数(Function) ,二者在语义、使用场景和特性上有显著区别。

代码展示:定义函数的两种方式

object base1500 {
  // 定义函数的方式一: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))  // 30
    println( getSum1(10,20))  // 30
  }
}

def 方法与函数字面量的核心区别

维度def 方法(Method)函数字面量(Function)
本质类 / 对象的成员,依附于作用域独立的值,FunctionN 特质的实例
是否为 “值”不是值,需通过 _ 转换为函数才能作为值传递是值,可直接赋值、传递或返回
命名必须有名称(方法名)本身匿名,需赋值给变量以复用
this 绑定有 this 指针(指向所在类 / 对象)无 this 指针(若捕获外部 this 则继承)
递归支持直接通过方法名递归,需显式返回值类型匿名函数无法直接递归,需借助 Y 组合子
常见场景类 / 对象的成员逻辑、工具方法高阶函数参数(如 map/filter)、回调逻辑

总结

  • def 用于定义方法,是类 / 对象的成员,适合封装与特定作用域相关的逻辑。
  • 函数字面量用于定义函数,是独立的值,适合需要传递、赋值的场景(如高阶函数、回调)。
  • 二者在语法和语义上有明确区分,但可通过 _ 相互转换,共同支撑 Scala 的函数式编程特性。

定义

除了使用def之外的,另一种定义函数的方式, 它省略了def,函数名以及函数的返回值类型。

语法

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

方法

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

  • 第一种方式为:_(占位符)。如果函数中的参数在方法体中只使用了一次,可以用 _ 替换。
  • 第二种方式为:只有一个表达式时,可以省略括号。

代码展示:函数字面量的简化写法

object base1501 {
  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))  // 30
    println( getSum1(10,20))  // 30
    println( getSum2(10,20))  // 30
    println( getSum3(10,20))  // 30
  }
}

二. 把函数作为参数💕前景提要💕

代码展示

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

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

  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)) // 30
    println( test(f2, 10, 20)) // 200
  }
}

代码分析

  1. 定义字面量函数
  • val f1: (Int, Int) => Int = _ + _:定义了一个函数 f1,它接受两个 Int 类型的参数,返回它们的和。这里的 _ + _ 是一种简洁的写法,等价于 (a: Int, b: Int) => a + b
  • val f2: (Int, Int) => Int = _ * _:定义了函数 f2,接受两个 Int 类型参数,返回它们的积,等价于 (a: Int, b: Int) => a * b
  1. 定义 test 函数
  • def test(fn: (Int, Int) => Int, x: Int, y: Int): Int = { fn(x, y) }test 函数有三个参数,第一个参数 fn 是一个函数类型(要求传入的函数接受两个 Int 参数并返回 Int),后两个参数 x 和 y 是 Int 类型。函数体是调用传入的 fn 函数,并用 x 和 y 作为参数,最后返回调用结果。
  1. main 方法(程序入口)
  • def main(args: Array[String]): Unit = { ... }:这是 Scala 程序的主入口方法。
  • println(test(f1, 10, 20)):调用 test 函数,传入 f1(做加法的函数)、10 和 20,执行后会计算 10 + 20,输出 30
  • println(test(f2, 10, 20)):调用 test 函数,传入 f2(做乘法的函数)、10 和 20,执行后会计算 10 * 20,输出 200

三. Scala部分应用函数

定义

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

代码展示

object base1506 {
  

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

  def main(args: Array[String]): Unit = {
    println(getSum(10, 20, 30)) // 60

    val t = getSum(10, 20, _) // t 就是部分应用函数!

    val t1 = getSum(_, 20, _) // t 就是部分应用函数!

    println(t(50))  // 80

    println(t1(20, 50))  // 90
  }
}

注意: 部分应用函数:

  • 如果一个函数需要3个参数,而我们只给了2个参数,会怎么样? 会报错:not enough arguments 可以通过补充参数的默认值来优化
   def getSum(a:Int, b:Int, c:Int = 0):Int = {
      a + b + c
   }
   
   
   def main(args: Array[String]): Unit = {
       println( getSum(10, 20, 30) )
       println( getSum(10, 20) )
    }
  • 如果一个函数需要 3 个参数,而我们只给了 2 个参数,另一个用 _ 来替代,会怎么样? 此时,函数不报错,能正常执行。 它的返回值是一个函数:部分应用函数