Swift如何使用类型擦除及自定义详解

2020-01-09 00:16:13王冬梅


class MAnySequence<Element>: Sequence {

这个类需要一个 iterator 类型作为 makeIterator 返回类型。我们必须要做两次类型擦除来隐藏底层的序列类型以及迭代器的类型。我们在 MAnySequence 内部定义了一个 Iterator 类,该类遵循着 IteratorProtocol 协议,并在 next() 方法中使用 fatalError 抛出异常。Swift 本身不支持抽象类型,但这样也够了:


class Iterator: IteratorProtocol {
 func next() -> Element? {
 fatalError("Must override next()")
 }
}

MAnySequence 对 makeIterator 方法实现也差不多。直接调用将抛出异常,这用来提示子类需要重写这个方法:


 func makeIterator() -> Iterator {
 fatalError("Must override makeIterator()")
 }
}

这样就定义了一个基于类的类型擦除的API,私有的子类将来实现这些API。公共类通过元素类型参数化,但私有实现类由它包装的序列类型进行参数化:


private class MAnySequenceImpl<Seq: Sequence>: MAnySequence<Seq.Element> {

MAnySequenceImpl 需要一个继承于 Iterator 的子类:


class IteratorImpl: Iterator {

IteratorImpl 包装了序列的迭代器:


var wrapped: Seq.Iterator

init(_ wrapped: Seq.Iterator) {
 self.wrapped = wrapped
}

在 next 方法中调用被包装的序列迭代器:


 override func next() -> Seq.Element? {
 return wrapped.next()
 }
}

相似地,MAnySequenceImpl 包装一个序列:


var seq: Seq

init(_ seq: Seq) {
 self.seq = seq
}

从序列中获取迭代器,然后将迭代器包装成 IteratorImpl 对象返回,这样就实现了 makeIterator 的功能。