不可变性与副作用
了解不可变性在函数式编程中的重要性,以及如何有效管理副作用。
不可变性与副作用 是 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 的最终目标是编写纯函数。纯函数具有两个关键特征:
- 对于相同的输入,它始终产生相同的输出(具有确定性)。
- 不会产生副作用(不会改变其作用域之外的任何内容)。
上一个示例中的 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 反馈 — 无需本地设置。