集合类型协议
1 Sequence协议
Sequence 协议是集合类型结构中的基础。一个序列 (sequence) 代表的是一系列具有相同类型的值,你可以对这些值进行迭代。 Sequence 协议提供了许多强大的功能,满足该协议的类型都可以直接使用这些功能。 如下是一个自定义实现Sequence的例子,Sequence协议提供很多功能,其中必须实现的只有一个迭代器,返回一个IteratorProtocol迭代器即可,所有关于Sequence的遍历筛选变形都是通过迭代器来实现的. 要实现自己的迭代器只需返回遵守IteratorProtocol协议的一个对象或者结构体即可.
//Sequence协议必须实现的部分 protocol Sequence { associatedtype Iterator: IteratorProtocol func makeIterator() -> Iterator } //菲波那切数列的Sequence实现方式 struct FibsQueue: Sequence { let number: Int init(_ number: Int) { self.number = number } typealias Iterator = FibsIterator func makeIterator() -> FibsQueue.Iterator { return FibsIterator(number) } }
2 IteratorProtocol协议
列通过创建一个迭代器来提供对元素的访问。迭代器每次产生一个序列的值,并且当遍历序列时对遍历状态进行管理。在 IteratorProtocol 协议中唯一的一个方法是 next(),这个方法需要在每次被调用时返回序列中的下一个值。当序列被耗尽时,next() 应该返回 nil.
// “protocol IteratorProtocol { associatedtype Element mutating func next() -> Element? } /// “FibsIterator 迭代器可以产生一个斐波那契序列。它将记录接下来的两个数字,并作为状态存储,next 函数做的事情是为接下来的调用更新这个状态,并且返回第一个数。和之前的例子一样,这个迭代器也将产生“无穷”的数字,它将持续累加数字” struct FibsIterator: IteratorProtocol { let number: Int var index: Int = 0 init(_ number: Int) { self.number = number } var state = (0,1) mutating func next() -> Int? { if index >= number { return nil } index += 1 let fibNumber = state.0 state = (state.1,state.0+state.1) return fibNumber } typealias Element = Int }
3 Collection协议
集合类型 (Collection) 指的是那些稳定的序列,它们能够被多次遍历且保持一致。除了线性遍历以外,集合中的元素也可以通过下标索引的方式被获取到。下标索引通常是整数,至少在数组中是这样。不过我们马上回看到,索引也可以是一些不透明值 (比如在字典或者字符串中),这有时候让使用起来不那么直观。集合的索引值可以构成一个有限的范围,它具有定义好了的开始和结束索引。也就是说,和序列不同,集合类型不能是无限的。
Collection协议是建立在Sequence协议上的. 除了从Sequence中集成了全部的方法以外,得益于可以获取指定位置的元素以及稳定迭代的保证,集合还获取了一些新的能力。比如 count 属性,如果序列是不稳定的,那么对序列计数将会消耗序列中的元素,这显然不是我们的目的。但是对于稳定的集合类型,我们就可以对其进行计数。
即使你用不到集合类型提供的这些特性,你依旧可以让你自己的序列满足 Collection 协议,这将告诉你的序列类型的使用者该序列是有限的,而且可以进行多次迭代。不过如果你只是想说明序列可以被多次迭代,但却必须去选一个合适的索引类型,确实会显得比较奇怪。在实现 Collection 协议时,最难的部分在于选取一个合适的索引类型来表达集合类型中的位置。这样设计的一个目的是,Swift 团队希望避免引入一个专门的可多次迭代序列的协议,因为它和 Sequence 拥有同样的要求,但是语义却不一致,这容易让用户感到迷惑。
//Collection协议,swift3,其中房噶和变量还是比较多的,但是很多都有了默认的实现,所以我们只需要实现少数几个即可 protocol Collection: Indexable,Sequence { associatedtype Iterator: IteratorProtocol = IndexingIterator<Self> associatedtype SubSequence: IndexableBase,Sequence = Slice<Self> associatedtype IndexDistance: SignedInteger = Int associatedtype Indices: IndexableBase,Sequence = DefaultIndices<Self> var first: Iterator.Element? { get } var indices: Indices { get } var isEmpty: Bool { get } var count: IndexDistance { get } func makeIterator() -> Iterator func prefix(through position: Index) -> SubSequence func prefix(upTo end: Index) -> SubSequence func suffix(from start: Index) -> SubSequence func distance(from start: Index,to end: Index) -> IndexDistance func index(_ i: Index,offsetBy n: IndexDistance) -> Index func index(_ i: Index,offsetBy n: IndexDistance,limitedBy limit: Index) -> Index? subscript(position: Index) -> Iterator.Element { get } subscript(bounds: Range<Index>) -> SubSequence { get } }
一个自定义实现FIFO队列的例子
//自定义一个队列 //首先定义好队列到底是什么,我们可以用协议来描述队列是社么 /// 一个能够将元素入队和出队的类型 protocol Queue { /// 在 `self` 中所持有的元素的类型 associatedtype Element /// 将 `newElement` 入队到 `self` mutating func enqueue(_ newElement: Element) /// 从 `self` 出队一个元素 mutating func dequeue() -> Element? } //实现一个队列,FIFO队列,其中元素类型是`Element` struct FIFOQueue<Element>: Queue { fileprivate var left: [Element] = [] fileprivate var right: [Element] = [] /// 将元素添加到队列最后 /// - 复杂度: O(1) mutating func enqueue(_ newElement: Element) { right.append(newElement) } /// 从队列前端移除一个元素 /// 当队列为空时,返回 nil /// - 复杂度: 平摊 O(1) mutating func dequeue() -> Element? { if left.isEmpty { left = right.reversed() right.removeAll() } return left.popLast() } } //遵守 Collection 协议 extension FIFOQueue: Collection { public var startIndex: Int { return 0 } public var endIndex: Int { return left.count + right.count } public func index(after i: Int) -> Int { precondition(i < endIndex) return i + 1 } public subscript(position: Int) -> Element { precondition((0..<endIndex).contains(position),"Index out of bounds") if position < left.endIndex { return left[left.count - position - 1] } else { return right[position - left.count] } } } //ExpressibleByArrayLiteral协议 extension FIFOQueue: ExpressibleByArrayLiteral { public init(arrayLiteral elements: Element...) { self.init(left: elements.reversed(),right: []) } }
4 ExpressibleByArrayLiteral协议
当实现一个类似队列这样的集合类型时,最好也去实现一下 ExpressibleByArrayLiteral。这可以让用户能够以他们所熟知的 [value1,value2,etc] 语法创建一个队列。
extension FIFOQueue: ExpressibleByArrayLiteral { public init(arrayLiteral elements: Element...) { self.init(left: elements.reversed(),right: []) } }
'Self' is only available in a protocol or as the result of a method in a class; ...
Reference: Swift进阶