我们来看AnySequence
的实现,通过这个过程,可以看到更多利用gyb
生成代码的用法。
AnySequence
的整体实现思路,和AnyIterator
几乎是一样的,也是通过一个_box
属性包装了原始序列类型。它的定义在这里:
public struct AnySequence<Element> {
internal let _box: _AnySequenceBox<Element>
}
从创建AnySequence说起
我们先把这个_AnySequenceBox
放一边,对一个类型的了解,从如何创建对象开始通常都是个不错的主意。希望你还记得,之前我们这样创建过一个AnySequence
:
let stdin = AnySequence(InputStream())
除了直接封装一个普通Sequence
之外,和AnyIterator
类似,我们可以直接给它传递一个生成Iterator
的closure:
let fibs = AnySequence<Int> {
() -> AnyIterator<Int> in
var state = (curr: 0, next: 1)
return AnyIterator {
let curr = state.curr
state = (curr: state.next, next: state.curr + state.next)
return curr
}
}
当然,从一开始AnySequence
的定义还可以推断,它应该还有一个memberwise init方法。因此,AnySequence
应该有三个init
:
public struct AnySequence<Element> {
internal let _box: _AnySequenceBox<Element>
public init<I : IteratorProtocol>(
_ makeUnderlyingIterator: @escaping () -> I
) where I.Element == Element {
self.init(_ClosureBasedSequence(makeUnderlyingIterator))
}
internal init(_box: _AnySequenceBox<Element>) {
self._box = _box
}
}
extension AnySequence: Sequence {
public typealias Iterator = AnyIterator<Element>
public init<S : Sequence>(_ base: S)
where
S.Element == Element {
self._box = _SequenceBox(_base: base)
}
}
其中:
- 第一个
init
对应的是通过closure创建AnySequence
; - 第二个
init
对应的是memberwise init; - 第三个
init
对应的是封装普通的Sequence
;
在上面这些代码里,有三个新类型:_AnySequenceBox
,_ClosureBasedSequence
以及_SequenceBox
。这感觉是不是有点儿熟悉?按照上一节分析AnyIterator
的经验,我们不难猜到:_AnySequenceBox
应该就是一个表示Sequence
的空壳,_SequenceBox
是_AnySequenceBox
的派生类,用于把对应的操作转发到包装的Sequence
对象。而_ClosureBasedSequence
就是把我们传递的closure变成makeIterator
方法的类。
然而,事实是否如此呢?
_ClosureBasedSequence
我们先从这个简单的_ClosureBasedSequence
开始。它的定义在这里:
internal struct _ClosureBasedSequence<Iterator : IteratorProtocol> {
internal var _makeUnderlyingIterator: () -> Iterator
internal init(_ makeUnderlyingIterator: @escaping () -> Iterator) {
self._makeUnderlyingIterator = makeUnderlyingIterator
}
}
extension _ClosureBasedSequence: Sequence {
internal func makeIterator() -> Iterator {
return _makeUnderlyingIterator()
}
}
果然,和我们猜想的是一样的。_ClosureBasedSequence
的作用,就是一个“万用Sequence
”,这个Sequence
的makeIterator
方法,执行的就是我们提供的closure。
_AnySequenceBox
接下来,是_AnySequenceBox
,它是通过gyb模板生成出来的类型,其中模板部分的定义在这里:
% for Kind in ['Sequence', 'Collection', 'BidirectionalCollection', 'RandomAccessCollection']:
% if Kind == 'Sequence':
internal class _AnySequenceBox<Element>
% elif Kind == 'Collection':
internal class _AnyCollectionBox<Element> : _AnySequenceBox<Element>
...
% end
从字面上,我们应该可以大致理解它的含义。首先,用for
循环遍历了一个数组,这个数组里,是要生成类型的protocols名称。其次,根据遍历结果,生成了以下几个类:
internal class _AnySequenceBox<Element>
internal class _AnyCollectionBox<Element>
internal class _AnyBidirectionalCollectionBox<Element>
internal class _AnyRandomAccessCollectionBox<Element>
顺着这个模板往下看,我们可以找到专门为Sequence
添加的方法:
{
% if Kind == 'Sequence':
internal init() { }
internal func _makeIterator() -> AnyIterator<Element> { _abstract() }
internal var _underestimatedCount: Int { _abstract() }
internal func _map<T>(
_ transform: (Element) throws -> T
) rethrows -> [T] {
_abstract()
}
internal func _filter(
_ isIncluded: (Element) throws -> Bool
) rethrows -> [Element] {
_abstract()
}
internal func _forEach(
_ body: (Element) throws -> Void
) rethrows {
_abstract()
}
/// ...
% end
这里为了简单,我只列出了部分方法,大家感受一下通过gyb模板生成类的方式就好。实际上,它们都是我们用过的各种Sequence
方法的“内部版本接口”。
_SequenceBox
最后,就剩下_SequenceBox
了。它的定义在这里:
internal final class _${Kind}Box<S : ${Kind}> : _Any${Kind}Box<S.Element>
{
/// ...
}
这里,${Kind}
就是之前遍历gyb数组时得到的值,对于Sequence
来说,翻译过来就是这样的:
internal final class _SequenceBox<S : Sequence> : _AnySequenceBox<S.Element>
{
/// ...
}
而它,就是AnySequence
中真正封装普通Sequence
的类型了。我们还是先从它的init
方法开始:
internal init(_base: S) {
self._base = _base
}
很简单,就是注入要封装的序列。
接下来_SequenceBox
重写了_AnySequenceBox
中定义的方法。简单起见,我们看两个例子:
internal override func _makeIterator() -> AnyIterator<Element> {
return AnyIterator(_base.makeIterator())
}
internal override func _map<T>(
_ transform: (Element) throws -> T
) rethrows -> [T] {
return try _base.map(transform)
}
基本上,就是把对应的操作转发给内部的_box
对象。
连接AnySequence和_SequenceBox
了解完_SequenceBox
之后,唯一剩下的问题,就变成了AnySequence
的操作是如何转发给内部的_SequenceBox
的呢?实际上,这是通过给AnySequence
添加了一组extension
实现的。它的定义在这里
% for Kind in ['Sequence', 'Collection', 'BidirectionalCollection', 'RandomAccessCollection']:
extension Any${Kind} {
% if Kind == 'Sequence':
public __consuming func makeIterator() -> Iterator {
return _box._makeIterator()
}
% end
public func map<T>(
_ transform: (Element) throws -> T
) rethrows -> [T] {
return try _box._map(transform)
}
}
可以看到,AnySequence
自身仍旧是通过gyb生成出来的。它的makeIterator
方法返回的就是_makeIterator()
的返回值,也就是说AnyIterator
是AnySequence
标配的Iterator
。而map
就是把方法转发给内部_box
对象的_map
方法,进而转发到真正包装的Sequence
对象。
网友评论