匿名函数与Lambda #

一、匿名函数基础 #

1.1 什么是匿名函数 #

匿名函数(也叫 Lambda 表达式)是没有名称的函数,通常作为参数传递给高阶函数。

1.2 基本语法 #

scala
(parameters) => body

1.3 简单示例 #

scala
val double = (x: Int) => x * 2
val add = (a: Int, b: Int) => a + b
val greet = (name: String) => s"Hello, $name!"

double(5)
add(10, 20)
greet("Scala")

二、匿名函数语法 #

2.1 单参数 #

scala
val isEven = (x: Int) => x % 2 == 0
val square = (x: Int) => x * x
val length = (s: String) => s.length

2.2 多参数 #

scala
val add = (a: Int, b: Int) => a + b
val max = (a: Int, b: Int) => if a > b then a else b
val format = (name: String, age: Int) => s"$name is $age years old"

2.3 无参数 #

scala
val getTimestamp = () => System.currentTimeMillis()
val random = () => scala.util.Random.nextInt()

getTimestamp()
random()

2.4 块表达式体 #

scala
val process = (x: Int) => {
  val doubled = x * 2
  val squared = doubled * doubled
  squared
}

val validate = (age: Int) => {
  if age < 0 then Left("Invalid age")
  else if age > 150 then Left("Age too high")
  else Right(age)
}

三、占位符语法 #

3.1 单占位符 #

当参数只使用一次时,可以用 _ 代替:

scala
val numbers = List(1, 2, 3, 4, 5)

numbers.map(x => x * 2)
numbers.map(_ * 2)

numbers.filter(x => x > 3)
numbers.filter(_ > 3)

numbers.foreach(x => println(x))
numbers.foreach(println(_))
numbers.foreach(println)

3.2 多占位符 #

scala
val add = (_: Int) + (_: Int)
val multiply = (_: Int) * (_: Int)

val numbers = List(1, 2, 3, 4, 5)
numbers.reduce((a, b) => a + b)
numbers.reduce(_ + _)

3.3 占位符的限制 #

占位符只能用于每个参数使用一次的情况:

scala
val double = (x: Int) => x * x
val double2 = _ * _

val diff = (a: Int, b: Int) => a - b
val diff2 = _ - _

val selfAdd = (x: Int) => x + x

3.4 类型推断 #

scala
val list = List(1, 2, 3, 4, 5)

list.map(_ * 2)
list.filter(_ > 3)
list.reduce(_ + _)

val strings = List("hello", "world")
strings.map(_.toUpperCase)
strings.filter(_.length > 4)

四、闭包 #

4.1 捕获外部变量 #

匿名函数可以捕获定义作用域中的变量:

scala
val factor = 10
val multiplier = (x: Int) => x * factor

multiplier(5)

4.2 修改捕获的变量 #

scala
var sum = 0
val numbers = List(1, 2, 3, 4, 5)

numbers.foreach(x => sum += x)
println(sum)

4.3 闭包示例 #

scala
def makeCounter(): () => Int =
  var count = 0
  () =>
    count += 1
    count

val counter1 = makeCounter()
val counter2 = makeCounter()

counter1()
counter1()
counter2()

4.4 闭包与函数返回 #

scala
def makeAdder(x: Int): Int => Int =
  y => x + y

val addFive = makeAdder(5)
val addTen = makeAdder(10)

addFive(3)
addTen(3)

五、匿名函数作为参数 #

5.1 传递给高阶函数 #

scala
val numbers = List(1, 2, 3, 4, 5)

val doubled = numbers.map((x: Int) => x * 2)
val evens = numbers.filter((x: Int) => x % 2 == 0)
val sum = numbers.reduce((a: Int, b: Int) => a + b)

5.2 类型推断 #

scala
val numbers = List(1, 2, 3, 4, 5)

val doubled = numbers.map(x => x * 2)
val evens = numbers.filter(x => x % 2 == 0)
val sum = numbers.reduce((a, b) => a + b)

5.3 简化形式 #

scala
val numbers = List(1, 2, 3, 4, 5)

val doubled = numbers.map(_ * 2)
val evens = numbers.filter(_ % 2 == 0)
val sum = numbers.reduce(_ + _)

六、匿名函数类型 #

6.1 函数类型语法 #

scala
val f1: Int => Int = x => x * 2
val f2: (Int, Int) => Int = (a, b) => a + b
val f3: () => String = () => "Hello"
val f4: String => Int => String = s => n => s * n

6.2 FunctionN 特质 #

scala
val f1: Function1[Int, Int] = x => x * 2
val f2: Function2[Int, Int, Int] = (a, b) => a + b
val f3: Function0[String] = () => "Hello"

6.3 方法转函数 #

scala
def double(x: Int): Int = x * 2

val doubleFunc: Int => Int = double
val doubleFunc2 = double _

七、模式匹配中的匿名函数 #

7.1 使用模式匹配 #

scala
val describe: Any => String = {
  case i: Int => s"Int: $i"
  case s: String => s"String: $s"
  case _ => "Unknown"
}

describe(42)
describe("hello")
describe(3.14)

7.2 偏函数 #

scala
val divide: PartialFunction[Int, Int] = {
  case d if d != 0 => 10 / d
}

divide.isDefinedAt(0)
divide.isDefinedAt(2)
divide(2)

7.3 collect 方法 #

scala
val numbers = List(1, 2, 3, 4, 5)

val evenStrings = numbers.collect {
  case n if n % 2 == 0 => s"even: $n"
}

八、实用示例 #

8.1 排序 #

scala
case class Person(name: String, age: Int)

val people = List(
  Person("Alice", 25),
  Person("Bob", 30),
  Person("Charlie", 20)
)

val byAge = people.sortBy(_.age)
val byName = people.sortBy(_.name)
val byAgeDesc = people.sortWith((a, b) => a.age > b.age)

8.2 分组 #

scala
val words = List("apple", "banana", "cherry", "date")

val byLength = words.groupBy(_.length)
val byFirstChar = words.groupBy(_.head)

8.3 聚合 #

scala
case class Sale(product: String, amount: Double)

val sales = List(
  Sale("A", 100),
  Sale("B", 200),
  Sale("A", 150),
  Sale("B", 250)
)

val byProduct = sales.groupMapReduce(_.product)(_.amount)(_ + _)

8.4 链式操作 #

scala
val result = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
  .filter(_ % 2 == 0)
  .map(_ * 2)
  .take(3)
  .sum

九、匿名函数最佳实践 #

9.1 保持简洁 #

scala
list.map(_ * 2)
list.filter(_ > 0)

list.map(x => x * x + 2 * x + 1)

9.2 使用有意义的参数名 #

scala
people.sortWith((p1, p2) => p1.age < p2.age)

people.sortWith((person1, person2) => person1.age < person2.age)

9.3 复杂逻辑使用命名函数 #

scala
def isEligible(person: Person): Boolean =
  person.age >= 18 && person.score > 60

people.filter(isEligible)

9.4 使用 for 推导式替代复杂链式调用 #

scala
val result = list
  .filter(_ > 0)
  .map(_ * 2)
  .filter(_ < 100)
  .map(_.toString)

val result2 = for
  x <- list
  if x > 0
  doubled = x * 2
  if doubled < 100
yield doubled.toString

十、总结 #

语法对比 #

语法 示例
完整形式 (x: Int) => x * 2
类型推断 x => x * 2
占位符 _ * 2
多参数 (a, b) => a + b
多占位符 _ + _

最佳实践 #

  1. 简单操作使用占位符语法
  2. 复杂逻辑使用命名函数
  3. 使用有意义的参数名
  4. 考虑使用 for 推导式提高可读性

下一步,让我们学习 柯里化

最后更新:2026-03-27