Swift3 IteratorProtocol

iteratorprotocol协议是紧密联系在一起的序列Sequence协议。序列通过创建一个迭代器来访问它们的元素,该迭代器跟踪其迭代过程,每次通过序列时返回一个元素。

无论何时使用数组、集合或任何其他集合或序列中的“在”for-in中,都使用该类型的迭代器。SWIFT在内部使用序列或集合的迭代器,以便在“for-in”语言构造中启用。
直接使用序列的迭代器使您能够以与'for - in'顺序相同的顺序访问相同的元素。例如,您可能通常使用“在”for - in ”来打印数组中的每一个元素。

let animals = ["Antelope", "Butterfly", "Camel", "Dolphin"]
for animal in animals {
    print(animal)
}

在后台,Swift使用“动物”数组的迭代器循环遍历数组的内容。

let animals = ["Antelope", "Butterfly", "Camel", "Dolphin"]
var animalIterator = animals.makeIterator()
while let animal = animalIterator.next() {
    print(animal)
}

命令 animals.makeiterator()返回数组的迭代器的实例。接下来的while循环反复的调用迭代器的next()方法,结合每个元素,返回animal,当退出时next()方法返回nil

========================
您很少需要直接使用迭代器,因为"for - in 循环"是更为符合语言习惯的快速遍历序列的方法。然而,有些算法可能要求直接迭代器使用。

一个例子是reduce1(_:)方法。类似的reduce(_: _:)方法在标准库定义的,这需要一个初始值和结合封闭,reduce1(_:)使用序列的第一个元素作为初始值。

这里的reduce1(_:)方法。序列的迭代器直接用于在循环其余的循环之前检索初始值。

extension Sequence {
    
    func reduce1(_ nextPartialResult: (Iterator.Element, Iterator.Element)  -> Iterator.Element ) -> Iterator.Element {
        
        var i = makeIterator()
        guard var accumulated = i.next() else {
            return (() -> ()).self as! Self.Iterator.Element
        }
        
        while let element = i.next() {
            accumulated = nextPartialResult(accumulated, element)
        }
        
        return accumulated
    }
}


// 注意: 在使用 Playground 的时候 " guard else " 的 return 如果返回 nil 报错

Playground execution failed: error: WYPlayground.playground:16:20: error: nil is incompatible with return type 'Self.Iterator.Element'
            return nil
                   ^

// 改成 

 guard var accumulated = i.next() else {
            return (() -> ()).self as! Self.Iterator.Element
        }
        

reduce1(_:)方法使某些种类的序列操作变得简单。下面是使用前面介绍的"animals"数组来查找序列中最长的字符串:

let logestAnimal = animals.reduce1 { (current, element) -> String in
    if current.characters.count > element.characters.count{
        return current
    } else {
        return element
    }
}
print( logestAnimal)

打印结果:
Butterfly

当您在一个序列中使用多个迭代器(或 for - in 循环),请确保您知道特定的序列支持重复迭代,或者因为您知道它的具体类型,或者因为该序列也受限于 "Collection" 协议。

从单独的调用获取每个单独的迭代器到序列的“makeIterator()”方法,而不是复制。复制迭代器是安全的,但是通过调用其“next()”方法来推送一个迭代器的一个副本可能会使该迭代器的其他副本无效。 for - in循环在这方面是安全的。

==============================

添加 IteratorProtocol 符合你的类型

实现符合“IteratorProtocol”的迭代器很简单。 声明一个next()方法,前进相关序列中的一个步骤并返回当前元素。 当序列耗尽时,next()方法返回nil

例如,考虑一个自定义的“倒计时”序列。 您可以使用起始整数初始化“倒计时”序列,然后将计数倒数计算为零。 “Countdown”结构的定义很短:它只包含“Sequence”协议所需的起始计数和“makeIterator()”方法。

struct Countdown: Sequence {
    let start: Int
    func makeIterator() -> CountdownIterator {
        return CountdownIterator(self)
    }
}

makeIterator()方法返回另一个自定义类型,称为“CountdownIterator”的迭代器。 “CountdownIterator”类型记录了它所进行迭代的“Countdown”序列和返回值的次数。

struct CountdownIterator: IteratorProtocol {
    let countdown: Countdown
    var times = 0
    init(_ countdown: Countdown) {
        self.countdown = countdown
    }
    
    mutating func next() -> Int? {
        
        let nextNumber = countdown.start - times
        guard nextNumber > 0 else {
            return nil
        }
        
        times += 1
        return nextNumber
    }
}

每次在“CountdownIterator”实例上调用next()方法时,它将计算新的下一个值,检查它是否已经达到零,然后返回数字,否则返回“nil”,如果迭代器完成 返回序列的元素。

在“Countdown”序列中创建和迭代使用“Countdown Iterator”来处理迭代。

let threeTwoOne = Countdown(start: 3)
for count in threeTwoOne {
    print("\(count)...")
}
/*
3...
2...
1...
*/
public mutating func next() -> Self.Element?

前进到下一个元素并返回它,如果没有下一个元素存在,则为“nil”。 重复调用此方法按顺序返回底层序列的所有元素。 一旦序列用完了元素,所有后续调用都返回nil。 如果此迭代器的任何其他副本已调用其“next()”方法,则不得调用此方法。 以下示例显示了如何显式地使用迭代器来模拟for -in循环。 首先,检索序列的迭代器,然后调用迭代器的“next()”方法,直到它返回“nil”。

let numbers = [2,3,5,7]
var numbersIterator = numbers.makeIterator()
while let num = numbersIterator.next() {
    print(num)
}

/*
2
3
5
7
*/
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,014评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,796评论 3 386
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,484评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,830评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,946评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,114评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,182评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,927评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,369评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,678评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,832评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,533评论 4 335
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,166评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,885评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,128评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,659评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,738评论 2 351

推荐阅读更多精彩内容