何时在Swift中使用序列,迭代器,集合等协议

时间:2019-07-15 03:36:54

标签: swift iterator protocols sequence comparable

我正在浏览快速教程,并且遇到了一些示例,这些示例实现了诸如Sequence,有时是Collection,有时是Iterator的协议

我查看了何时真正使用此协议,但从未找到。所有其他材料都说明了如何使用它,但没有说明何时使用。

有人可以建议我在哪里可以学到这个。任何快速提示都将真正有帮助。

谢谢

1 个答案:

答案 0 :(得分:2)

为特定类型(例如Array)编写例程通常是最简单的,但是例如,为Sequence协议编写它们可以提供更大的灵活性。在编写集合扩展时,我通常会遇到这种情况,根据定义,扩展可以在其他地方重用,并且灵活性具有最大的价值。

例如,考虑此Array扩展名来求和:

extension Array where Element == Int {
    func sum() -> Int {
        var sum = 0
        for element in self {
            sum += element
        }
        return sum
    }
}

如果您确实有一个数组,例如,

let total = [1, 2, 3].sum()    // fine

但是,如果您有范围,那将不起作用,例如:

let total = (1...3).sum()      // this won’t work

您必须将其转换为数组才能工作:

let total = Array(1...3).sum() // this will work, but introduces a little syntactic noise

但是,您可以将扩展名定义为Array,而不是将其定义为Sequence扩展名:

extension Sequence where Element == Int {
    func sum() -> Int {
        var sum = 0
        for element in self {
            sum += element
        }
        return sum
    }
}

看起来几乎一样,但是此表示法适用于任何序列(例如,数组和范围),例如:

let total1 = [1, 2, 3].sum()    // this is still fine ...
let total2 = (1...3).sum()      // but now, this now works as intended, too

还有一些我可能更喜欢特定类型协议的示例:

  • 在编写接受字符串输入的例程时,我可能会将其编写为接受StringProtocol,以便该例程同时接受字符串和子字符串(例如string[start..<end])。

  • 在处理范围时,我采用了类似的思维过程,理想情况下,算法应在封闭范围,开放范围,部分范围等条件下工作。在需要一定灵活性的情况下,我将使用RangeExpression ,而我在寻找快速简单的内容时只会使用Range

话虽这么说,通常为特定类型编写方法要比为协议编写方​​法更简单,因此人们应该在通过使用协议提供的灵活性与为特定类型编写方法的简便性之间取得平衡。就个人而言,如果这是一些不会在其他地方使用的私有方法,那么我将继续编写简单的,特定于类型的演绎法,但是如果它是一些公共/内部实用程序方法,并且可能会得到一些重用,那么我会使用协议格式实现最大的灵活性。

在编写方法时,最重要的是,请问自己,该方法仅适用于Array类型是否很重要,或者是否有其他顺序可以使用同一例程。


就我何时为自己的类型使用Sequence或迭代器而言,这种情况很少见。我将在编写真正的“序列”时执行此操作,在此情况下,下一个值是根据之前的值生成的,例如斐波那契数列或此count-and-say sequence。您可以在调用点与序列进行一些非常自然的交互,而不必将结果塞入数组。但是,在现实应用程序中,我们遇到这种模式的机会几乎没有简单数组那么频繁。