1️⃣ Functor 特性在 Publisher 中的体现
Functor 核心:能够把函数映射到容器/上下文中的值,同时保持结构不变。
在 Combine 中:
Publisher可以看作一个 容器,异步发出值- 使用
map可以对 Publisher 发出的每个元素进行函数映射 - 不改变 Publisher 的结构,只改变输出值
示例
import Combine
import Foundation
let publisher = [1, 2, 3].publisher // ArrayPublisher<Int>
let mapped = publisher.map { $0 * 2 }
let cancellable = mapped.sink { value in
print("Mapped value:", value)
}
// 输出:Mapped value: 2
// Mapped value: 4
// Mapped value: 6
map只改变 输出值,不改变 Publisher 的类型- 多次
map可组合,满足 Functor 规律:
let f: (Int) -> Int = { $0 + 1 }
let g: (Int) -> Int = { $0 * 10 }
let left = publisher.map(f).map(g)
let right = publisher.map { g(f($0)) }
left==right✅ 组合律满足
2️⃣ Monad 特性在 Publisher 中的体现
Monad 核心:支持 bind(flatMap)操作,能够把返回容器的函数平铺,避免嵌套容器。
在 Combine 中:
flatMap对应 Monad 的 bind- 输入:
(Output) -> Publisher<NewOutput, Failure> - 输出:单一 Publisher,把可能产生的多个嵌套 Publisher 平铺
- 支持链式组合多个异步操作
示例
假设我们有两个异步 Publisher 函数:
func fetchNumber(_ id: Int) -> AnyPublisher<Int, Never> {
Just(id * 2).eraseToAnyPublisher()
}
func fetchString(_ number: Int) -> AnyPublisher<String, Never> {
Just("Number is (number)").eraseToAnyPublisher()
}
// 使用 flatMap 链式组合
let cancellable2 = [1, 2, 3].publisher
.flatMap { fetchNumber($0) } // Monad bind,平铺 Publisher
.flatMap { fetchString($0) }
.sink { print($0) }
解释:
-
[1,2,3].publisher→ Publisher -
.flatMap(fetchNumber)→ Publisher- 每个值会生成一个新的 Publisher
- flatMap 平铺输出,而不是产生嵌套 Publisher<Publisher>
-
.flatMap(fetchString)→ Publisher -
最终输出一个 扁平 Publisher,可以订阅
3️⃣ Functor vs Monad 对比在 Combine 中
| 特性 | Functor (map) | Monad (flatMap) |
|---|---|---|
| 操作类型 | (Output) -> NewOutput | (Output) -> Publisher<NewOutput, Failure> |
| 结构变化 | 不改变 Publisher 层级 | 平铺嵌套 Publisher |
| 适用场景 | 对值做同步转换 | 异步链式调用,生成新的 Publisher |
| 示例 | .map { $0 * 2 } | .flatMap { fetchNumber($0) } |
4️⃣ 总结
-
Functor
Publisher.map→ 映射输出值,保持 Publisher 结构- 遵循恒等和组合律
-
Monad
Publisher.flatMap→ 绑定新的 Publisher,平铺嵌套,短路失败可处理- 支持函数式异步流水线,链式组合
💡 核心思想:
Combine 的 Publisher 就是一个 异步容器,Functor 和 Monad 的特性保证了:
- 可以安全映射数据 (
map)- 可以安全组合异步操作 (
flatMap)- 异步值处理保持函数式风格,副作用集中在
sink或assign