美文网首页
Swift5 通过gyb生成AnySequence

Swift5 通过gyb生成AnySequence

作者: 醉看红尘这场梦 | 来源:发表于2020-03-11 18:03 被阅读0次

我们来看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”,这个SequencemakeIterator方法,执行的就是我们提供的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()的返回值,也就是说AnyIteratorAnySequence标配的Iterator。而map就是把方法转发给内部_box对象的_map方法,进而转发到真正包装的Sequence对象。

相关文章

网友评论

      本文标题:Swift5 通过gyb生成AnySequence

      本文链接:https://www.haomeiwen.com/subject/uyjhjhtx.html