swift 源码解析 -- Sequence
常用功能分析
Sequence作为swift集合类协议扩展方法,为集合提供了一系列的序列迭代能力。最为常用的for-in,快速枚举遍历,都是通过此协议提供了最基础的迭代能力。
let animals = ["monkey", "tigger", "bird", "horse", "zebra"]
for animal in animals {
print("animal : (animal)")
}
// animal : monkey
// animal : tigger
// animal : bird
// animal : horse
// animal : zebra
不仅如此,swift集合中的众多高阶函数,例如:map,fliter,reduce,flatMap等也都是该协议提供的方法,还有,contains,min,max等等,也都是其提供的方法。可以说,尽管代码不多,但是能力却相当强大。
let animals = ["monkey", "tigger", "bird", "horse", "zebra"]
print("animal : (animals.min())")
// animal : Optional("bird")
对于min的使用当然不止这么简单,还可以采用传入条件的形式:
let animals = ["monkey", "tigger", "bird", "horse", "zebra"]
print("animal : (animals.min(by: >))")
// animal : Optional("zebra")
传入大于号的方式显然是错的,但是通过这样的实验,也证明了其函数式的可构造性十分强大。那么其源码是如何实现的呢?
实现分析
迭代方法实现展示:
public protocol Sequence {
// 类型占位符
// 可在协议实现后确定协议类型
associatedtype Element
// 这是一个重要的东西
// 迭代器的实现核心
associatedtype Iterator: IteratorProtocol where Iterator.Element == Element
}
public protocol IteratorProtocol {
// 用于查找下一个对象
// 如果找不到的话就返回nil
mutating func next() -> Element?
}
// 来自于/collection目录
// collection协议的延展中实现IteratorProtocol事例
extension IndexingIterator: IteratorProtocol, Sequence {
public typealias Element = Elements.Element
public typealias Iterator = IndexingIterator<Elements>
public typealias SubSequence = AnySequence<Element>
// 从实现可以看出
// 容器协议通过元素位置对于迭代器进行next返回
@inlinable
@inline(__always)
public mutating func next() -> Elements.Element? {
if _position == _elements.endIndex { return nil }
let element = _elements[_position]
_elements.formIndex(after: &_position)
return element
}
}
extension Collection where Iterator == IndexingIterator<Self> {
// 生产迭代器,并返回
@inlinable
@inline(__always)
public __consuming func makeIterator() -> IndexingIterator<Self> {
return IndexingIterator(_elements: self)
}
}
通过上面源代码可以知道每个序列协议内部,都存在一个迭代器协议,迭代器的内部接口其实十分简单,只是规定了next协议方法,但是这也很符合接口单一原则。通过协议不同实现,从而达到不同算法复杂度的结果。
在滚动占位符的设计中,利用了自定义迭代器的方法,从而使外部传入的数据集合到达可循环,可洗牌,可重新获取等目的。
public struct YouaInfiniteIterator<Iterator: IteratorProtocol>: IteratorProtocol {
// 生成两个迭代器
// 一个负责存储数据
// 另一个负责当前迭代使用
private let sampleIterator: Iterator
private var currentIterator: Iterator
// 是否可重复
public var isRepeats: Bool = true
public init(_ sample: Iterator) {
self.sampleIterator = sample
self.currentIterator = sampleIterator
}
public mutating func next() -> Iterator.Element? {
// 如果当前迭代对象不为空
// 则继续执行
if let next = currentIterator.next() {
return next
} else if isRepeats == false {
return nil
} else {
// 迭代末端重新注入数据
self.currentIterator = sampleIterator
return currentIterator.next()
}
}
}
public extension IteratorProtocol {
func infinite() -> YouaInfiniteIterator<Self> {
return YouaInfiniteIterator(self)
}
}
这样可以在不修改数据结构的情况下,实现可重复容器。
在sequence的源码中,也扩展了例如DropFirstSequence,PrefixSequence等,对于迭代器进行了单独的处理封装,可以阅读代码了解。
除了对于迭代器的描述,高阶函数,也是swift中极为重要的特性,也是函数式编程中十分重要的实现手段,以高阶函数中最为基础的map函数为例:
extension Sequence {
@inlinable
public func map<T>(
_ transform: (Element) throws -> T
) rethrows -> [T] {
// Collection.underestimatedCout 容器预估数量
// 初始化空间
let initialCapacity = underestimatedCount
var result = ContiguousArray<T>()
result.reserveCapacity(initialCapacity)
var iterator = self.makeIterator()
// 先加入预估的一波
for _ in 0..<initialCapacity {
result.append(try transform(iterator.next()!))
}
// 再将剩下的元素加进去
while let element = iterator.next() {
result.append(try transform(element))
}
return Array(result)
}
}
尽管swift中高阶函数的实现方式,并没有采用递归的方式,但是,这里也符合柯里化思想。大体上,swift中迭代器实现的高阶函数,都是通过for-in与block结合使用,支持泛型,也可以扩展协议。
此外,还有一个方法需要注意一下。
@inlinable
public func contains(_ element: Element) -> Bool {
if let result = _customContainsEquatableElement(element) {
return result
} else {
return self.contains { $0 == element }
}
}
在默认条件下,contains方法是通过泛型中"=="方法来确定是否存在包含关系,可以通过运算符重载来达到多种对比的逻辑要求,例如,正常判断两个对象的引用地址(如果是值类型,则判断值),但如果这样的话,可能会导致判断失败,如果对象中包含属性id,则可以重载运算符,对比两个对象的id。
也可以通过增加协议实现_customContainsEquatableElement方法,达成以上目的。