何时使用forEach(_ :)而不是for?

时间:2017-07-26 16:58:07

标签: swift loops foreach sequence for-in-loop

正如ArrayDictionary forEach(_:)实例方法中所述:

  

序列中的每个元素上调用给定的闭包   订购为for-in循环。

然而,改编自Sequence Overview

  

序列是一个值列表,您可以在a处逐步执行一个值   时间。 迭代序列元素的最常用方式   是使用 for-in循环

暗示按forEach(_:)for in迭代序列:

let closedRange = 1...3

for element in closedRange { print(element) } // 1 2 3

closedRange.forEach { print($0) } // 1 2 3

或(数组):

let array = [1, 2, 3]

for element in array { print(element) } // 1 2 3

array.forEach { print($0) } // 1 2 3

会给出相同的输出。

为什么forEach(_:)甚至存在?即使用它而不是for in循环有什么好处?从性能观点来看,它们是否相同?

作为假设,它可能是一种语法糖,特别是在使用函数式编程时。

4 个答案:

答案 0 :(得分:49)

forEach没有提供任何性能优势。事实上,if you look at the source codeforEach函数实际上只是执行for - in。对于发布版本,此函数的性能开销比仅使用for - in本身并不重要,但对于调试版本,它会导致可观察到的性能影响。

forEach的主要优点是在进行函数式编程时实现,您可以将它添加到一系列函数调用中,而不必将先前的结果保存到您需要的单独变量中使用了for - in语法。所以,而不是:

let objects = array.map { ... }
    .filter { ... }

for object in objects {
    ...
}

你可以保持在函数式编程模式中:

array.map { ... }
    .filter { ... }
    .forEach { ... }

结果是功能代码更简洁,语法噪音更少。

FWIW,ArrayDictionarySequence的文档都提醒我们forEach引入的限制,即:

  
      
  1. 您无法使用breakcontinue语句退出当前语句   调用body关闭或跳过后续调用。

  2.   
  3. 使用return闭包中的body语句将仅从中退出   当前对body的调用,而不是来自任何外部范围,并且不会跳过   后续电话。

  4.   

答案 1 :(得分:10)

我最近遇到了一个使用forEach的用例,以for in为切实可行。我们假设您要从图层中删除所有子图层。如下所示的声明不起作用,因为您需要打开[CALayer]

for layer in self.videoContainerView.layer.sublayers!

如果子图层为零,则会发生崩溃。这会强制您先检查是否有子图层。但是,forEach使这更加简单,如下所示:

self.videoContainerView.layer.sublayers?.forEach { $0.removeFromSuperlayer() }

答案 2 :(得分:7)

它们或多或少是可以互换的,但有两个重要的区别。

  1. break / continue仅适用于for .. in
  2. return中的
  3. forEach将退出闭包,但不会停止迭代。
  4. 原因是for .. in是语言中的特殊形式(允许中断并继续按预期工作)。您可以使用语言本身以相同的方式实现这一点。

    但是,forEach不是一种特殊形式,可以通过将其写为函数来重新实现。

    extension Sequence {
        func myOwnForEach(_ body: (Self.Element) throws -> Void) rethrows {
            let it = Self.makeIterator()
            while let item = it.next() {
                body(item)
            }
        }
    }
    

答案 3 :(得分:0)

除了上述答案之外,还有一个将 for 循环与 forEach 区分开来的原因是使用 for 循环,我们还可以选择使用基于 where 的模式来实现该逻辑匹配,例如

for adBanner in adBanners where !adBanner.isLoading {

上述与控制流相关的功能使 for 循环如此强大,但如果我们不需要这种级别的控制,则使用对 forEach 的调用可能会使我们的代码看起来稍微简单一些。

简而言之,使用 for 循环可以让我们更好地控制迭代