3-14.【函数式编程】在 Swift 中如何使用纯函数和副作用分离实现数据处理流水线?

2 阅读1分钟

1️⃣ 核心思路

目标:把数据处理逻辑设计成可组合的流水线,同时:

  1. 核心处理逻辑保持纯函数
  2. 副作用(打印、网络、文件写入)集中在最外层

原则

  • 纯函数 → 只处理数据,不依赖外部状态
  • 副作用函数 → 接收纯函数输出,执行打印/存储/网络等

流水线 = 多个纯函数组合 → 最终执行副作用


2️⃣ 示例场景

假设我们有一个字符串数组,需要做以下处理:

  1. 去除长度 ≤ 3 的字符串
  2. 转成大写
  3. 统计每个字符串长度
  4. 输出日志(副作用)

3️⃣ 使用纯函数 + 副作用分离实现

步骤 1:定义纯函数

// 过滤短字符串
func filterShortStrings(_ strings: [String]) -> [String] {
    return strings.filter { $0.count > 3 }
}

// 转大写
func toUpperCase(_ strings: [String]) -> [String] {
    return strings.map { $0.uppercased() }
}

// 计算长度
func stringLengths(_ strings: [String]) -> [Int] {
    return strings.map { $0.count }
}
  • 输入 → 输出完全由参数决定
  • 无打印、无修改外部状态
    ✅ 都是纯函数

步骤 2:组合流水线

func processData(_ strings: [String]) -> [Int] {
    let filtered = filterShortStrings(strings)
    let uppercased = toUpperCase(filtered)
    return stringLengths(uppercased)
}
  • 可以链式调用或组合纯函数
  • 流水线核心逻辑完全纯净

步骤 3:集中副作用

func printResult(_ results: [Int]) {
    print("Processed string lengths:", results)
}
  • 只在最后一步打印,副作用集中
  • 核心处理逻辑不依赖打印

步骤 4:使用

let words = ["apple", "is", "good", "for", "health"]

let lengths = processData(words) // 纯函数流水线
printResult(lengths)             // 副作用执行

// 输出:Processed string lengths: [5, 4, 6]

4️⃣ 可进一步函数式优化

可以使用链式函数式写法(更简洁):

let lengths = ["apple", "is", "good", "for", "health"]
    .filter { $0.count > 3 }
    .map { $0.uppercased() }
    .map { $0.count }  // 纯函数链

print("Processed string lengths:", lengths) // 副作用在这里
  • 流水线逻辑完全纯函数化
  • 副作用只在最后的 print

5️⃣ 优势

优势说明
可测试核心函数无副作用,可单元测试
可组合每个函数独立,可重用或组合
并发安全纯函数天然线程安全
易维护副作用集中管理,逻辑清晰

总结设计模式

  1. 纯函数层 → 数据转换、过滤、映射、计算
  2. 副作用层 → 日志打印、文件写入、网络请求
  3. 流水线执行 → 纯函数处理数据 → 副作用层执行最终输出