设计原理
为什么错误类型不是泛型
enum Event<Element> {
case Next(Element) // next element of a sequence
case Error(ErrorType) // sequence failed with error
case Completed // sequence terminated successfully
}
让我们来讨论一下,如果 ErrorType
是泛型的优劣点。
如果你有一个错误类型的泛型,你创建两个 observable 之间的额外阻抗失配。
比如你有:
Observable<String, E1>
和 Observable<String, E2>
没有多少,你可以与他们无关不搞清楚所产生的错误类型是什么
它可能是 E1
, E2
或是新的 E3
?所以你可能需要一组操作符,只是用来解决阻抗失配。
这破坏了组件属性,并且 Rx 并不关心一个序列为什么失败,他通常只是进一步转发失败下的 observable 链。
这是另一个问题,在某些情况下,操作符也许会因为内部错误失败,在那种情况下,你将不能构建一个结果错误,并且报告失败。
不过还好,让我们忽略那个,并且假设我们能用那个区模型化不会错误退出的序列。这会对那个目的有用吗?
好吧是的,它可能会有效,但是让我们想想,你为什么需要使用不会错误退出的序列。
一个平淡无奇的应用是用不变的流来驱动整个UI用户界面。当你考虑那个例子,只用编译器来保证序列不出错退出真的是不够的,你还需要保证其他属性。比如说,元素需要被观察在 MainScheduler
上。
你真正需要是一个通用的方法来验证 observable 序列的特性。这有许多属性你可能感兴趣。举个例子:
- 序列终止于有限的时间内(服务端)
- 序列只包含一个元素(如果你在运行一些计算)
- 序列不错误退出,从不终止并且在主调度器(UI)上接收元素。
- 序列不错误退出,从不终止并且在主调度器上接收元素,而且有引用计数分享(UI)
- 序列不错误退出,从不终止并且在特殊的调度器上接收元素(音频引擎)
你真的想要的是一个通用的强制编译的 observable 序列特性系统,以及那些想要属性的不变式操作符集合。
一个适当的类比:
1, 3.14, e, 2.79, 1 + 1i <-> Observable<E>
1m/s, 1T, 5kg, 1.3 pounds <-> Errorless observable, UI observable, Finite observable ...
在 Swift 中可以用很多方式实现这个事情,比如使用组合或者继承 observables。
使用单位系统的另一个好处是你可以验证 UI 的代码在同一个调度器(scheduler)上执行,然后在所有转变中使用无所操作。
因为 RxSwift 的单序列操作符已经没有锁,所有的锁存在于稳定的组件中(例如,UI),实际上 RxSwift 的代码中不含有锁,因此允许强制编译。
当保留 Rx 组件的语义时使用 Error 泛型是真的没有好处并不能达到一个清晰的方式。