集合类型协议
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进阶