Related articles:
Swift Advancement (Built-in Set Type) - A Record of the Growth of a Non-disciplinary Ban Nung
2017.08.09
sequence
Sequence protocol is the basis of set type structure. A sequence represents a series of values of the same type that you can iterate over.
Meeting the requirements of the Sequence protocol is very simple. All you need to do is provide a makeIterator() method that returns iterators:
protocol Sequence{ associatedtype Iterator: IteratorProtocol func makeIterator() -> Iterator }
iterator
protocol IteratorProtocol{ associatedtype Element mutating func next() -> Element? }
You often see Iterator.Element, which is actually defined in Iterator Protocol.
Essentially, the for loop is a short form of the following code:
var some = [1, 2, 3, 4] var iterator = some.makeIterator() //For loop is short for this code while let element = iterator.next() { print(element) }
You can also create a wireless, never-ending sequence. The simplest case is an iterator that keeps returning the same value.
struct ConstantIterator: IteratorProtocol{ typealias Element = Int mutating func next() -> Int? { return 1 } } var iter = ConstantIterator() //while let x = iter.next() { // print(x) // // This is a dead cycle. //}
Next, let's look at a more interesting example: FibsIterator iterator can produce a Fibonacci sequence.
struct FibsIterator:IteratorProtocol{ var state = (0,1) //Adding mutating modifiers to modify your state mutating func next() -> Int?{ let upNum = state.0 state = (state.1, state.0 + state.1) return upNum } } var fibs = FibsIterator() while let fib = fibs.next() { //Stop judging, or it will cycle to death. guard fib < 145 else { break } print(fib) }
Compliance with Sequence Protocol
struct PrefixIterator: IteratorProtocol{ let string: String var offset: String.Index init(string:String) { self.string = string offset = string.startIndex } mutating func next() -> String? { guard offset < string.endIndex else { return nil } offset = string.index(after: offset) return string[string.startIndex..<offset] } } //Remember to block the custom protocol at the beginning, otherwise error will be reported: type'PrefixSequence'does not conform to protocol'Sequence' struct PrefixSequence: Sequence{ let string: String func makeIterator() -> PrefixIterator{ return PrefixIterator.init(string: string) } } var prefix = PrefixSequence.init(string: "Hello") for char in prefix { print(char) } var pre = PrefixIterator.init(string: "World") while let p = pre.next() { print(p) } //Replace all with capitals let ma = prefix.map({ $0.uppercased() }) ma
Iterator and Value Semantics
let seq = stride(from: 0, to: 10, by: 1) var i1 = seq.makeIterator() i1.next() //0 i1.next() //1 var i2 = i1 i2.next() //2 i2.next() //3 i1.next() //2 i1.next() //3 //i1 and i2 are separate and independent. //An Iterator Example without Value Semantics var i3 = AnyIterator(i1) var i4 = i3 i3.next() //4 i4.next() //5 i3.next() //6 i4.next() //7 //Sharing an iterator
Function-based iterators and sequences
Fibonacci iterator is defined by a function that returns AnyIterator:
func fibsIterator() -> AnyIterator<Int>{ var state = (0, 1) return AnyIterator{ let upNum = state.0 state = (state.1, state.0 + state.1) return upNum } } let fibsSequence = AnySequence.init(fibsIterator()) Array.init(fibsSequence.prefix(10)) //[0, 1, 1, 2, 3, 5, 8, 13, 21, 34] Array.init(fibsSequence.prefix(2)) //[55, 89]
The sequence function introduced in Swift 3 has two versions. First, sequence(first:next:) takes the value of the first parameter as the first element of the sequence, and uses the closure passed in by the next parameter to generate the subsequent elements of the sequence. In the following example, we generate a sequence of random numbers in which each element is smaller than the previous one until it reaches zero:
let randomNumbers = sequence(first: 100) { (previous: UInt32) in let newValue = arc4random_uniform(previous) guard newValue > 0 else { return nil } return newValue } Array.init(randomNumbers) //[100, 14, 8, 6, 2]
The other is sequence(state:next:), which is more powerful because it can save arbitrary variable state between two next closures being called. We can use it to construct Fibonacci sequences through a single method call.
let fibs2 = sequence(state: (0, 1)) { (state: inout(Int, Int)) -> Int? in let upNum = state.0 state = (state.1, state.0 + state.1) return upNum } Array.init(fibs2.prefix(10)) //[0, 1, 1, 2, 3, 5, 8, 13, 21, 34] Array.init(fibs2.prefix(3)) //[0, 1, 1]
Reading makes me doze off. = Search found that the information conversion rate is not good, or indeed the code foundation is too poor!!!