3-20.【函数式编程】请实现一个链式调用多个可能失败的函数,并用 flatMap / map 处理错误。

5 阅读1分钟

1️⃣ 定义错误类型和函数

import Foundation

enum ParseError: Error {
    case invalidNumber
}

enum AppError: Error {
    case parseFailed
    case negativeValue
}

// 函数 1:字符串转 Int
func parseInt(_ str: String) -> Result<Int, ParseError> {
    if let n = Int(str) {
        return .success(n)
    } else {
        return .failure(.invalidNumber)
    }
}

// 函数 2:增加 10,但不能为负
func addTen(_ x: Int) -> Result<Int, AppError> {
    let result = x + 10
    if result >= 0 {
        return .success(result)
    } else {
        return .failure(.negativeValue)
    }
}

// 函数 3:翻倍
func double(_ x: Int) -> Result<Int, AppError> {
    return .success(x * 2)
}
  • parseInt 返回 Result<Int, ParseError>
  • addTendouble 返回 Result<Int, AppError>
  • 我们将演示 链式调用 + 错误映射

2️⃣ 链式调用 + flatMap

let input = "5"

let result = parseInt(input)
    // 将 ParseError 映射为 AppError
    .mapError { _ in AppError.parseFailed }
    // 链式调用 addTen
    .flatMap(addTen)
    // 链式调用 double
    .flatMap(double)

switch result {
case .success(let value):
    print("Final Result:", value)
case .failure(let error):
    print("Error:", error)
}

解释

  1. parseInt 可能失败 → 返回 Result<Int, ParseError>

  2. 使用 mapErrorParseError 映射为统一的 AppError

  3. 使用 flatMap(addTen) 链式调用

    • 如果前一步成功 → 执行 addTen
    • 如果失败 → 错误直接传递
  4. 使用 flatMap(double) 链式调用翻倍

  5. 最终 resultResult<Int, AppError>


3️⃣ 测试不同输入

let inputs = ["5", "-20", "abc"]

for input in inputs {
    let result = parseInt(input)
        .mapError { _ in AppError.parseFailed }
        .flatMap(addTen)
        .flatMap(double)

    switch result {
    case .success(let value):
        print("Input:", input, "=>", value)
    case .failure(let error):
        print("Input:", input, "=> Error:", error)
    }
}

输出示例

Input: 5 => 30     // (5 + 10) * 2
Input: -20 => Error: negativeValue   // (-20 + 10 < 0)
Input: abc => Error: parseFailed     // 无法解析

4️⃣ 优势

  • 链式调用无需嵌套 switchtry/catch
  • 错误通过 mapError / flatMap 自动传递
  • 核心逻辑保持 纯函数 + 函数组合
  • 易于测试每个单独函数