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

Ahm*_*d F 26 foreach loops sequence for-in-loop swift

数组字典 forEach(_:)实例方法中所述:

以与for-in循环相同的顺序调用序列中每个元素的给定闭包.

然而,改编自序列概述:

序列是一个值列表,您可以一次单步执行一个值.迭代序列元素的最常用方法是使用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
Run Code Online (Sandbox Code Playgroud)

或(数组):

let array = [1, 2, 3]

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

array.forEach { print($0) } // 1 2 3
Run Code Online (Sandbox Code Playgroud)

会给出相同的输出.

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

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

Rob*_*Rob 59

没有提供的性能优势forEach.事实上,如果你看一下源代码,这个forEach函数实际上只是简单地执行for- in.对于发布版本,此函数的性能开销仅仅使用for- in自己是无关紧要的,但对于调试版本,它会导致可观察到的性能影响.

forEach当您进行函数式编程时,可以实现主要优点,您可以将其添加到函数调用链中,而无需将先前结果保存到您使用的单独变量中for- in语法.所以,而不是:

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

for object in objects {
    ...
}
Run Code Online (Sandbox Code Playgroud)

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

array.map { ... }
    .filter { ... }
    .forEach { ... }
Run Code Online (Sandbox Code Playgroud)

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

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

  1. 您不能使用breakor continue语句退出当前的body闭包调用或跳过后续调用.

  2. 使用闭包中的return语句body将仅从当前调用退出body,而不是从任何外部作用域退出,并且不会跳过后续调用.

  • 关于链接的好点子。这对我来说并不明显,我有几个地方要转换为 .forEach 正是因为这个原因。 (2认同)

pli*_*nth 11

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

  1. break/ continue只在一个for .. in
  2. returnforEach将退出关闭,但不会停止迭代.

原因在于它for .. in是语言中的一种特殊形式(允许中断并继续按预期工作).这是你无法使用语言本身以相同的方式实现的东西.

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

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


C6S*_*ver 11

我最近碰到了一个用例,其中使用forEach是有形的for in.假设您要从图层中删除所有子图层.如下所示的声明不起作用,因为您需要打开包装[CALayer]

for layer in self.videoContainerView.layer.sublayers!
Run Code Online (Sandbox Code Playgroud)

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

self.videoContainerView.layer.sublayers?.forEach { $0.removeFromSuperlayer() }
Run Code Online (Sandbox Code Playgroud)