当前位置: 首页>>代码示例 >>用法及示例精选 >>正文


Swift IteratorProtocol用法及代码示例


协议

IteratorProtocol

一种一次提供一个序列值的类型。

声明

protocol IteratorProtocol<Element>

概述

IteratorProtocol 协议与Sequence 协议紧密相连。序列通过创建一个迭代器来提供对其元素的访问,该迭代器跟踪其迭代过程并在它通过序列时一次返回一个元素。

每当您使用带有数组、集合或任何其他集合或序列的 for - in 循环时,您都在使用该类型的迭代器。 Swift 在内部使用序列或集合的迭代器来启用 for - in 循环语言结构。

直接使用序列的迭代器可以让您以与使用 for - in 循环迭代该序列相同的顺序访问相同的元素。例如,您通常可以使用 for - in 循环来打印数组中的每个元素。


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

在幕后,Swift 使用 animals 数组的迭代器来循环数组的内容。


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

animals.makeIterator() 的调用返回数组迭代器的一个实例。接下来,while 循环重复调用迭代器的 next() 方法,绑定每个返回到 animal 的元素,并在 next() 方法返回 nil 时退出。

直接使用迭代器

您很少需要直接使用迭代器,因为 for - in 循环是在 Swift 中遍历序列的更惯用的方法。然而,一些算法可能需要直接使用迭代器。

一个示例是reduce1(_:) 方法。与标准库中定义的reduce(_:_:) 方法类似,该方法采用初始值和组合闭包,reduce1(_:) 使用序列的第一个元素作为初始值。

这是reduce1(_:) 方法的实现。序列的迭代器直接用于在遍历序列的其余部分之前检索初始值。


extension Sequence {
    func reduce1(
        _ nextPartialResult: (Element, Element) -> Element
    ) -> Element?
    {
        var i = makeIterator()
        guard var accumulated = i.next() else {
            return nil
        }


        while let element = i.next() {
            accumulated = nextPartialResult(accumulated, element)
        }
        return accumulated
    }
}

reduce1(_:) 方法使某些类型的序列操作更简单。下面以前面介绍的animals数组为例,说明如何查找序列中最长的字符串:


let longestAnimal = animals.reduce1 { current, element in
    if current.count > element.count {
        return current
    } else {
        return element
    }
}
print(longestAnimal)
// Prints Optional("Butterfly")

使用多个迭代器

每当您在单个序列上使用多个迭代器(或 for - in 循环)时,请确保您知道特定序列支持重复迭代,因为您知道它的具体类型或因为序列也被限制为 Collection 协议。

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

将IteratorProtocol 一致性添加到您的类型

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

例如,考虑一个自定义 Countdown 序列。您可以使用起始整数初始化Countdown 序列,然后将计数迭代到零。 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 序列使用 CountdownIterator 来处理迭代。


let threeTwoOne = Countdown(start: 3)
for count in threeTwoOne {
    print("\(count)...")
}
// Prints "3..."
// Prints "2..."
// Prints "1..."

可用版本

iOS 8.0+, iPadOS 8.0+, macOS 10.10+, Mac Catalyst 13.0+, tvOS 9.0+, watchOS 2.0+

相关用法


注:本文由纯净天空筛选整理自apple.com大神的英文原创作品 IteratorProtocol。非经特殊声明,原始代码版权归原作者所有,本译文未经允许或授权,请勿转载或复制。