※この記事はSwift by Sundellの内容を日本語に翻訳したものです。
Array
やSet
などのコレクションを反復処理する場合、最初は、従来のfor
ループを使用するか、クロージャーベースのforEach
メソッドを使用するかは、好みとスタイルの問題のように思われるかもしれません。これらの2つのメカニズムが非常に類似していることは確かですが、いくつかの点で異なります。
これらの違いの1つは、for
ループの反復がコードの制御フロー内で直接実行されることです。これにより、これらの反復をより正確に制御できます。たとえば、continue
キーワードを使用して任意の時点で次の要素にスキップするか、break
を使用して反復を完全に中断するかを選択できます。
func recentArticles(among articles: [Article]) -> [Article] {
var results = [Article]()
for article in articles {
guard !article.isDraft else {
// すぐに次の要素にスキップします。
continue
}
results.append(article)
guard results.count < 5 else {
// 反復を中断します。この場合、ここに直接戻ることもできます。
break
}
}
return results
}
for
ループの反復が(上記のように)フィルタリングに使用されるguard
(またはif
)ステートメントで始まる場合、代わりにwhere
ベースのパターンマッチングを使用してそのロジックを実装することもできます—次のように:
for article in articles where !article.isDraft {
results.append(article)
guard results.count < 5 else {
break
}
}
上記の種類の制御フロー関連の機能は、forループを非常に強力にする大きな部分ですが、そのレベルの制御が必要ない場合は、forEach
の呼び出しを使用すると、コードが少し単純に見える可能性があります。たとえば、ここでは、配列の要素ごとに新しいビューを追加しています。これは、forEach
を使用して非常にエレガントに実行できます。
func addArticleViews(for articles: [Article]) {
articles.forEach { article in
let articleView = ArticleView()
// クロージャーの article を使用して新しいビューを設定します。
...
view.addSubview(articleView)
}
}
ただし、Swiftのファーストクラス関数機能を使用する方がおそらくさらにエレガントです。上記のメソッドをリファクタリングして単一のArticle
のみを受け入れ、そのメソッドをforEach
の呼び出しに直接挿入します。
class ArticleGroupViewController: UIViewController {
private let articles: [Article]
...
override func viewDidLoad() {
super.viewDidLoad()
...
articles.forEach(addArticleView)
}
private func addArticleView(for article: Article) {
let articleView = ArticleView()
...
view.addSubview(articleView)
}
}
要約すると、for
ループを使用すると、反復をより高度に制御できます。一方、forEach
を使用すると、一度開始すると反復を停止することはできませんが、クロージャとファーストクラス関数の機能を利用できます(エラーをスローすることは別として)。
元の記事
Picking between a for loop and forEach Swift by Sundell