Array と Dictionary の両方で文書化されているforEach(_:)
インスタンスメソッド:
For-inループと同じ順序でsequenceの各要素で指定されたクロージャーを呼び出します。
それにもかかわらず、 シーケンスの概要 から適応:
シーケンスは、一度に1つずつステップ実行できる値のリストです。 シーケンスの要素を反復する最も一般的な方法は、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
_ループの代わりにそれを使用する利点は何ですか?パフォーマンスの観点からは同じでしょうか?
前提として、特に関数型プログラミングを使用する場合は、構文上の砂糖になる可能性があります。
forEach
によるパフォーマンス上の利点はありません。実際、 ソースコードを見ると の場合、forEach
関数は実際には単にfor
-in
を実行します。リリースビルドの場合、単にfor
-in
を使用するだけの場合のこの関数のパフォーマンスオーバーヘッドは重要ではありませんが、デバッグビルドの場合は、パフォーマンスに目に見える影響があります。
forEach
の主な利点は、関数型プログラミングを行うときに実現されます。関数呼び出しのチェーンに追加できます。for
-in
構文を使用した場合に必要な別の変数に以前の結果を保存する必要はありません。したがって、代わりに:
let objects = array.map { ... }
.filter { ... }
for object in objects {
...
}
代わりに、関数型プログラミングパターン内にとどまることができます。
array.map { ... }
.filter { ... }
.forEach { ... }
その結果、構文上のノイズが少なく、より簡潔な機能コードが作成されます。
FWIW、 Array 、 Dictionary 、および Sequence のドキュメントはすべて、forEach
によって導入された制限を思い出させます:
break
またはcontinue
ステートメントを使用して、body
クロージャーの現在の呼び出しを終了したり、後続の呼び出しをスキップしたりすることはできません。
return
クロージャーでbody
ステートメントを使用すると、現在のbody
の呼び出しからのみ終了し、外部スコープからは終了せず、後続の呼び出しをスキップしません。
私は最近、for in
よりも具体的な方法でforEach
を使用することが望ましいユースケースに出くわしました。レイヤーからすべてのサブレイヤーを削除するとします。以下のようなステートメントは、[CALayer]
をアンラップする必要があるため機能しません
for layer in self.videoContainerView.layer.sublayers!
サブレイヤーがゼロの場合、クラッシュします。これにより、最初にサブレイヤーがあるかどうかを確認する必要があります。ただし、forEach
を使用すると、次のようにこれがはるかに簡単になります。
self.videoContainerView.layer.sublayers?.forEach { $0.removeFromSuperlayer() }
それらは多かれ少なかれ互換性がありますが、2つの重要な違いがあります。
break
/continue
は、for .. in
return
のforEach
はクロージャを終了しますが、反復を停止しません。その理由は、for .. in
は、言語では特別な形式です(これにより、期待どおりに中断して作業を続けることができます)。言語自体を使用して同じ方法で実装することはできません。
ただし、forEach
は特別な形式ではなく、関数として記述することで同じように再実装できます。
extension Sequence {
func myOwnForEach(_ body: (Self.Element) throws -> Void) rethrows {
let it = Self.makeIterator()
while let item = it.next() {
body(item)
}
}
}