CodeRoadMap
首页路线题库资源库文章社区
CodeRoadMap

程序员的学习成长路线图。内容免费开放,登录后可同步路线图与课时进度。

由 程序员柏风 独立维护 · 关于作者

学习

  • 路线图
  • 课程
  • 面试题
  • 文章
  • 我

更多

  • 资源
  • 社区
  • 关于作者
  • 内容说明

© 2026 CodeRoadMap

津ICP备2026012044号-1·津公网安备12011002026155号·coderoadmap@126.com
Scala 语言入门/课时/函数式编程
RawBlame
课时目录12 节

Scala 语言入门

  1. 01Scala 是什么
  2. 02基础语法
  3. 03OOP 与模式匹配
  4. 04集合与高阶函数
  5. 05函数式编程
  6. 06类型系统
  7. 07构建工具
  8. 08后端框架
  9. 09数据与 JSON
  10. 10测试
  11. 11并发与流
  12. 12综合练习

函数式编程

纯函数、Either/Try、尾递归。

35 分钟

函数式编程

Scala 鼓励纯函数、不可变数据与显式错误建模。Either、Try 替代异常驱动流程;尾递归优化避免深递归栈溢出。对照 /roadmaps/scala「Functional Programming」节点。

学习目标

  • 区分纯函数与副作用,理解引用透明性
  • 使用 Either、Try 表达失败路径
  • 编写 @tailrec 尾递归函数

核心概念

纯函数与不可变

def addAll(xs: List[Int]): Int =
  xs.sum   // 不修改 xs,无副作用

def withBonus(scores: Map[String, Int], user: String, bonus: Int): Map[String, Int] =
  scores.updated(user, scores.getOrElse(user, 0) + bonus)

val base = Map("alice" -> 90)
val updated = withBonus(base, "alice", 5)
println(base("alice"))      // 90 不变
println(updated("alice"))   // 95

纯函数相同输入恒得相同输出;不可变数据结构通过 copy/updated 返回新实例。

Either 与 Try

def parseId(s: String): Either[String, Long] =
  s.toLongOption.toRight(s"invalid id: $s")

def loadTitle(id: Long): Either[String, String] =
  if id > 0 then Right(s"Bookmark #$id")
  else Left(s"not found: $id")

def loadBookmark(rawId: String): Either[String, String] =
  for
    id <- parseId(rawId)
    title <- loadTitle(id)
  yield title

import scala.util.{Try, Success, Failure}

def safeDivide(a: Int, b: Int): Try[Double] =
  Try(a.toDouble / b)

println(loadBookmark("42"))
println(loadBookmark("abc"))
println(safeDivide(10, 0))

Either 的 for comprehension 在 Left 时短路;Try 捕获非 fatal 异常,适合与 Java 互操作边界。

尾递归

import scala.annotation.tailrec

@tailrec
def factorial(n: Int, acc: BigInt = 1): BigInt =
  if n <= 1 then acc
  else factorial(n - 1, acc * n)

@tailrec
def findIndex[A](xs: List[A], pred: A => Boolean, idx: Int = 0): Int =
  xs match
    case Nil => -1
    case h :: t if pred(h) => idx
    case _ :: t => findIndex(t, pred, idx + 1)

println(factorial(20))
println(findIndex(List(1, 3, 5, 7), _ == 5))

@tailrec 要求递归调用在最后一行,编译器优化为循环;无注解的深递归可能 StackOverflowError。

与 Java 对照

ScalaJava
纯函数 + 不可变可变 DTO 常见
Either[L, R]异常 / Result 类型(需库)
Try[T]try-catch
@tailrec手动 while 循环
for 推导短路多层 flatMap

Java 近年引入 Stream 与 Optional,但默认仍偏命令式;Scala 函数式是语言级习惯。

练习

  • 用 Either 实现链式校验:邮箱格式 + 非空标题
  • 将递归 sum(List[Int]) 改写为 @tailrec 版本
  • 对比 Java 抛异常与 Scala Either 在 API 设计上的利弊

小结

纯函数、Either/Try、尾递归是 Scala FP 的实战三角。 下一课类型系统与隐式。见 scala-essentials。

加载本节练习…
← 上一课集合与高阶函数下一课 →类型系统