Sequence 协议是集合类型结构中的基础. 我们经常会对一个Array 或者Dictionary进行for 循环迭代正是因为它们遵守了Sequence协议并实现了迭代方法.
自然是一个协议,我们可以自定义一个类型来遵守它,也可以实现自己想要的迭代操作.
比如当前有一个整数10086, 有需求要取出这个数中从个位,十位,百位..到最高位的数..如果是字符串"10086" 我们可以直接对字符串序列进行遍历
for i in "10086" {
print(i)
}
在Swift标准库总String类型是遵守了Sequence协议的,上图代码会根据字符串索引从第0个打印到它最后一个.
然而如果我们直接对10086这个int类型的整数进行for in 操作,编译器会告诉我们Type 'Int' does not conform to protocol 'Sequence'
没错,Int 当然不是一个序列.不遵守这个协议,无法进行迭代操作.
我们先来看一下Sequence协议是怎么定义的
protocol Sequence {
associatedtype Iterator: IteratorProtocol
func makeIterator() -> Iterator
}
满足一个Sequence协议的要求只有一个,,提供一个满足IteratorProtocol协议(迭代器协议)返回值的方法..很直接,我们实现它的目的也正是为了迭代.
/// InteratorProtocol 的定义如下
protocol IteratorProtocol {
associatedtype Element
mutating func next() -> Element?
}
关联类型 Element 指定了迭代器产生的值的类型. 比如String的迭代器的元素类型是Character. 在处理Sequence的泛型约束的时候我们经常会使用Iterator.Element, 这里的Element就是IteratorProtocl中定义的..
这个协议中只有一个 next方法,用来返回迭代的元素.可以使用for循环遍历的原因是for循环在背后帮我们做了一件事就是不断的调用迭代器的next方法,直到返回nil为止,
/// for循环做的事情实际是下面这个的简写模式
var iterator = someSequence.makeIterator()
while let element = iterator.next() {
print(element)
}
接下来完成我们的需求:
// 因为遍历一个Int的迭代器系统中没有,需要我们自己创建
struct NumberIterator: IteratorProtocol {
typealias Element = Int
var number: Int
var offset = 1
init(_ number: Int) {
self.number = number
}
// IteratorPtocol中要求实现的函数
mutating func next() -> NumberIterator.Element? {
// 根据当前的offset返回个位/十位...数
guard number / offset >= 1 else {return nil}
offset = offset * 10
return number / (offset / 10) % 10
}
}
// 我们直接使用的序列
struct NumberSequence: Sequence {
let number: Int // 其中只有一个int型的属性
// Sequence要求实现的函数,返回一个迭代器,把我们刚才实现的迭代器返回.当然迭代器需要一个number值.
func makeIterator() -> NumberInterator {
return NumberInterator(number)
}
}
现在我们成功创建好了自己的序列类型 NumberSequence,想要直接迭代一个Int类型的整数:
for prefix in NumberSequence(193835) {
print(prefix)
}
直接转换成新的Sequence类型就可以进行迭代了..
在实际应用中,如果想要迭代某一个数据类型,让它遵守Sequence协议并且实现响应的方法就可以了.
网友评论