# Swift 集合類型之迭代器

Blai
Blai

咱們知道在 SwiftSequence集合類型結構 中的基礎。而在 Sequence 協議的定義當中咱們能夠看到有這麼一句代碼 :bash

associatedtype Iterator : IteratorProtocol複製代碼

咱們看到有兩個關鍵字:associatedtypeIteratorProtocolide

1.associatedtype

那麼這個 associatedtype 是什麼意思呢?
看個例子就知道了:函數

第一步:

咱們定義兩個協議 A,B,協議 B 中用到了協議 Aui

protocol A {}
protocol B {
    func action(_ pA2: A)
}複製代碼
第二步:

那麼咱們對協議 A 有兩個實現: A1A2.
咱們對協議 BB1 的實現.代碼以下:this

struct A1: A {}
struct A2: A {}

struct B1: B {
    func action(_ pA2: A) {
        print("我只認對協議A實現的A2")
    }
}複製代碼

這個時候若是咱們要使用 B1 的時候,能夠這樣:spa

let action = B1()
action.action(A2())
action.action(A1())

///我只認對協議A實現的A2
///我只認對協議A實現的A2複製代碼
第三步: 條件

這個時候咱們在 B1 中對傳入協議 A 的類型想要指定的類型實現而傳入非指定類型的實現編譯器就會報錯怎麼作?
有人講這樣:指針

struct B1: B {
    func action(_ pA2: A2) {
        print("我只認對協議A實現的A2")
    }
}複製代碼

這樣子編譯器就會報錯:Type 'B1' does not conform to protocol 'B'
這個時候咱們的 associatedtype 就能夠登場了:code

protocol A {}
protocol B {
    associatedtype F: A
    func action(_ pA2: F)
}

struct A1: A {}
struct A2: A {}

struct B1: B {
    func action(_ pA2: A2) {
        print("我只認對協議A實現的A2")
    }
}

let action = B1()
action.action(A2())
///action.action(A1())  這個實現就直接報錯了:error: OptimizingCollections.playground:16:15: error: cannot convert value of type 'A1' to expected argument type 'A2' action.action(A1())複製代碼

associatedtype 總結就仁者見仁各有各的理解啦!小插曲結束進入正題:↓orm

2.IteratorProtocol 與迭代器的邂逅

按住 Command 點進去會發現該協議只有一個函數:cdn

associatedtype Element
public mutating func next() -> Self.Element?複製代碼

如下用 next() 來表示.

可別看它就這麼一句;,可是 能量 很大!!!

迭代器 是一個知足 IteratorProtocol 協議的類型。

普及一個知識:

序列 (Sequence)

具備相同類型的值的一個集合吧。好比簡單的: [Int] ... 都是知足 Sequence 協議
的。


那麼有了序列就會有須要對值遍歷的訪問,那麼就是靠建立一個 迭代器 來進行對元素的訪問。
那麼 next() 的做用就是每次調用的時候返回序列的下一個值,直到最後一個返回 nil

這裏來開始剖析:

Self.Element

它是一個關聯類型用來指定 next() 所產生值的元素類型,好比咱們常常見到的 Iterator.Element 就是 IteratorProtocol 中的定義 Element。那麼迭代器通常會用在那裏呢?

答:自定義序列的擴展類型,好比你想經過字符串 "YinYu" 轉換爲:"["Y", "i", "n", "Y", "u"]" 的擴展類等等等等多的用途!

迭代器在結構上是單向的,顧名思義只能一路 next
對於迭代器相似的操做咱們通常都是用

for <#item#> in <#items#> {
    <#code#>
}複製代碼

來完成。 這個通常狀況是不推薦使用的。咱們要玩就要玩高級的。否則怎麼成長呢?是吧!

接下來咱們來完成這樣一個例子的實現,來爲您之後 「拋磚引玉」 一下

首先完成一個 PrefixIterator 實現 IteratorProtocol協議的 struct

public struct PrefixIterator: IteratorProtocol {
    let string: String
    var offset: String.Index
    init(string: String) {
        self.string = string
        offset = string.startIndex
    }
    mutating public func next() -> String? {
        guard offset < string.endIndex else { return nil }
        let previousSet = offset
        offset = string.index(after: offset)
        return String(string[previousSet..<offset])
    }
}複製代碼

咱們分析上面主要有: mutating,字符串切片(String(string[previousSet..<offset]))
那麼有了迭代器,就須要一個裝載迭代器的且知足 Sequence 協議的 struct.
由於在 Sequence 中咱們發現有這樣的一個函數:

associatedtype Iterator : IteratorProtocol

///Returns an iterator over the elements of this sequence
public func makeIterator() -> Self.Iterator複製代碼

那麼這裏咱們的 PrefixIterator 就至關於 Self.Iterator 類型.
接下來就實現對 Sequence協議的構造。

public struct PrefixSequence: Sequence {
    let string: String
    public func makeIterator() -> PrefixIterator {
        return PrefixIterator(string: string)
    }
}複製代碼

既然實現了 Sequence協議,那麼咱們就能夠獲得 Map, filter, forEach, dropFirst... 這些集合類型經常使用的函數方法。
利用 Map依次返回一個字母。從而達到 "YinYu""Y", "i", "n", "Y", "u" 的轉換
這樣一個 String 擴展方法就出來了:

extension String {
    func stringToArr() -> [String] {
        return PrefixSequence(string: self).map { $0 }
    }
}複製代碼
let strs = "YinYu".stringToArr()
/// ["Y", "i", "n", "Y", "u"]複製代碼

固然若是你想輸出的字面都是大寫很簡單:
$0.uppercased() 這樣就OK啦.

值語義

咱們都知道 結構體(Struct) 枚舉(enum)值類型

當建立一個 class(類) 的時候,class 是 引用類型

對於引用類型的操做咱們是要萬分當心的,引用類型是具備統一性的通常用 === 判斷兩個變量是否引用了同一個 object。即:指針相等
== 呢? 固然是: 結構相等

通常咱們經過值類型是否執行 深複製來判斷是否具備 值語義.

有深複製就會有 潛複製:
Struct 中包含引用類型,這個時候 Struct 進行賦值給其它的變量的時候所發生的複製行爲會存在引用類型的內容是不會複製,其引用自己會被複制。這種行爲就是 淺複製.


AnyIterator

能夠對其它的迭代器進行一個包裝,從而迷惑使用者。

這裏要說的就是 AnyIterator 在這樣的狀況下 var 新迭代器 = AnyIterator(舊迭代器) 的時候, 新迭代器是 不具備 值語義的。這種狀況下舊迭代器與新迭代器就不是單獨的了,新迭代器就不是一個結構體。 新迭代器是以一個類實例。
下面代碼見分曉:

var ierator1 = stride(from: 0, to: 10, by: 1).makeIterator()

ierator1.next()   /// 0
ierator1.next()   /// 1

var ierator2 = ierator1

ierator1.next()   /// 2
ierator1.next()   /// 3

ierator2.next()   /// 2
ierator2.next()   /// 3

var ierator3 = AnyIterator(ierator1)
var ierator4 = ierator3

ierator3.next()   /// 4
ierator4.next()   /// 5

ierator3.next()   /// 6
ierator3.next()   /// 7複製代碼

AnySequence

彷佛與 IteratorSequence 同樣,也存在着 AnySequence.

AnyIterator 也是對 IteratorProtocol 協議的實現.那麼配合 nest() 與對應的 AnySequence,能夠獲得在不定義任何新類型的狀況下建立迭代器序列。

語歌博客: Blog.aiyinyu.com
語歌-Blair

相關文章
相關標籤/搜索