3-12.【函数式编程】请举例说明一个有副作用的函数,并给出纯函数替代实现。

3 阅读1分钟

1️⃣ 有副作用的函数示例

假设我们要实现一个累加器,每次调用函数都会累加值并打印:

var total = 0

func addAndPrint(_ x: Int) -> Int {
    total += x              // 修改外部变量 → 副作用
    print("Total:", total)   // 打印 → 副作用
    return total
}

addAndPrint(5) // Total: 5
addAndPrint(3) // Total: 8

分析

  • 副作用 1:修改了外部变量 total
  • 副作用 2:打印输出
  • 非纯函数原因:同样输入 x = 3,每次返回值可能不同(依赖 total 的当前值)

2️⃣ 纯函数替代实现

纯函数的思路:不依赖外部状态、不修改外部变量、输出只依赖输入

func add(_ x: Int, to total: Int) -> Int {
    return total + x
}

// 使用:
let total1 = add(5, to: 0) // 5
let total2 = add(3, to: total1) // 8

print("Total1:", total1) // Total1: 5
print("Total2:", total2) // Total2: 8

特点

  • 输入:xtotal
  • 输出:total + x
  • 不修改外部变量
  • 同样输入总是得到同样输出

3️⃣ 优势对比

特性有副作用函数纯函数
输出是否确定不确定(依赖外部状态)确定(只依赖输入)
是否修改外部状态
并发安全❌ 需要加锁✅ 天然线程安全
可组合性差,容易引发 bug好,可与其他函数组合

4️⃣ 使用场景示例

如果我们要累加数组元素:

有副作用写法

var total = 0
[1,2,3].forEach { total += $0 }
print(total) // 6

纯函数写法

let total = [1,2,3].reduce(0, +)
print(total) // 6
  • reduce + 闭包是纯函数
  • 没有修改外部状态
  • 可安全并发、可预测

💡 总结

副作用 = 修改外部状态或产生不可控影响
纯函数替代 = 所有状态通过输入参数传入,输出仅依赖输入