0Pricing
Scala for Backend Engineering & Functional Programming · 课时

不可变性与副作用

了解不可变性在函数式编程中的重要性,以及如何有效管理副作用。

不可变性与副作用 是 CoddyKit 上的免费 Scala for Backend Engineering & Functional Programming 课时。 这是第 3 节课,共 3 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Scala for Backend Engineering & Functional Programming 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Scala for Backend Engineering & Functional Programming 课程共包含 3 节课。

以设计实现不可变

欢迎学习不可变性与副作用!这些是函数式编程(FP)中的核心概念,有助于我们编写更简洁、更可预测的代码。

在 FP 中,我们倾向于使用不可变数据。这意味着数据一旦创建,就不能再更改。您可以把它想象成一张照片——您可以查看它,但无法改变它所记录的那个时刻。

Scala 中的 val 与 var

Scala 使用 val 关键字可以轻松声明不可变值。这是一个常量引用,在初次定义后不能重新赋值。对于可变变量,则应使用 var。

让我们看看它们的区别:

object Main {
  def main(args: Array[String]): Unit = {
    // Immutable value
    val greeting = "Hello"
    // greeting = "Hi" // This would cause a compile error!

    // Mutable variable
    var count = 0
    count = 1 // This is allowed

    println(greeting)
    println(count)
  }
}

不可变性为何重要

不可变性为代码带来了多项强大优势,尤其适用于并发且复杂的系统:

  • 可预测性:您始终可以确定值不会意外改变。
  • 并发安全:程序的多个部分可以读取相同数据,而不必担心其他部分修改它。无需复杂的锁!
  • 更易调试:由于不必担心状态随时间变化,定位错误会更加简单。

不可变集合

Scala 的标准库默认大力采用不可变集合。当您“修改”不可变集合时,实际上会得到一个包含这些更改的新集合,而原集合保持不变。

下面是使用不可变 List 的示例:

object Main {
  def main(args: Array[String]): Unit = {
    val numbers = List(1, 2, 3)
    val newNumbers = numbers :+ 4 // Creates a new list

    println(s"Original list: $numbers")
    println(s"New list: $newNumbers")
  }
}

理解副作用

与不可变性相对,副作用是指函数或表达式除了返回值之外还执行了其他操作。它会与“外部世界”交互,或改变可变状态。

常见的副作用包括:

  • 修改全局变量或可变对象。
  • 向控制台打印内容(I/O)。
  • 写入文件或数据库。
  • 更改系统时钟。

副作用带来的问题

虽然副作用有时不可避免,但在函数式编程中,我们的目标是尽量减少并隔离副作用。为什么呢?

  • 更难推理:函数的输出可能取决于外部状态,因此难以预测。
  • 难以测试:测试需要设置和清理外部状态。
  • 并发问题:多个线程执行副作用可能导致竞态条件和错误。

识别代码中的副作用

让我们看一个 Scala 示例。其中一个函数有副作用,另一个没有。您能找出区别吗?

object Main {
  var total = 0 // A mutable global variable

  // Function with a side effect
  def addAndPrint(x: Int, y: Int): Int = {
    total = x + y // Modifies global state
    println(s"Sum is: $total") // I/O side effect
    total
  }

  // Function without side effects (pure function)
  def pureAdd(x: Int, y: Int): Int = {
    x + y // Only returns a value
  }

  def main(args: Array[String]): Unit = {
    addAndPrint(5, 3)
    println(s"Global total: $total")
    println(s"Pure sum: ${pureAdd(5, 3)}")
  }
}

纯函数:FP 的理想形式

FP 的最终目标是编写纯函数。纯函数具有两个关键特征:

  1. 对于相同的输入,它始终产生相同的输出(具有确定性)。
  2. 不会产生副作用(不会改变其作用域之外的任何内容)。

上一个示例中的 pureAdd 函数就是纯函数!

管理副作用

由于某些副作用不可避免(例如打印结果或保存数据),FP 采取的方法是:

  • 隔离副作用:将带有副作用的函数与纯函数分开。
  • 将副作用推向边缘:在程序开始或结束时执行 I/O,或在专门的“有副作用”部分中执行。
  • 使用 FP 构造:库通常会提供类型(例如 IO 或 Task)来明确表示和管理副作用。

检查您的理解

根据您所学的内容,以下哪项关于函数式编程中不可变性和副作用的说法是 TRUE?

回顾:不可变性与副作用

做得很好!在本课中,我们探讨了函数式编程中不可变性和副作用这两个重要概念。

  • 我们了解了 val 如何在 Scala 中促进不可变性,从而带来更可预测且更安全的并发代码。
  • 我们将副作用定义为函数返回值之外的交互,并理解了它们为何会使代码变得复杂。
  • 最后,我们学习了作为 FP 理想形式的纯函数:它们具有确定性且没有副作用;我们还学习了管理必要副作用的策略。

掌握这些概念是编写健壮而优雅的函数式 Scala 应用的关键!

常见问题解答

「不可变性与副作用」课时是免费的吗?

是的 — 「不可变性与副作用」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Scala for Backend Engineering & Functional Programming 课程的其余内容,请升级到 CoddyKit PRO。 Scala for Backend Engineering & Functional Programming 课程共包含 3 节课。

「不可变性与副作用」这节课中我会学到什么?

了解不可变性在函数式编程中的重要性,以及如何有效管理副作用。 你通过在浏览器中直接运行的动手代码来练习 Scala for Backend Engineering & Functional Programming,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 Scala for Backend Engineering & Functional Programming 需要有经验吗?

无需任何先前经验。CoddyKit 上的 Scala for Backend Engineering & Functional Programming 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 3 节课,共 3 节。

「不可变性与副作用」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 Scala for Backend Engineering & Functional Programming 课中编写并运行代码吗?

能。每节 Scala for Backend Engineering & Functional Programming 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. 作为一等值的函数
  2. 高阶函数与柯里化
  3. 不可变性与副作用
← 返回 Scala for Backend Engineering & Functional Programming