Хотя оба подхода используются для итерации по коллекциям, между ними есть ключевые различия, которые важно понимать для правильного выбора в разных ситуациях.
let numbers = [1, 2, 3]
for number in numbers {
print(number)
}
numbers.forEach { number in
print(number)
}
for-in:
break и continuereturn для выхода из текущей итерации (но не из функции)for number in numbers {
if number == 2 { break } // Прерывает весь цикл
print(number)
}
forEach:
break и continuereturn внутри замыкания ведет себя как continuenumbers.forEach { number in
if number == 2 { return } // Эквивалентно continue
print(number)
}
for-in может быть чуть быстрее для простых операцийforEach может быть оптимизирован для некоторых коллекцийfor-in с индексами:
for index in numbers.indices {
print(numbers[index])
}
forEach с индексами:
numbers.enumerated().forEach { index, number in
print("\(index): \(number)")
}
В forEach сложнее обрабатывать ошибки из-за замыкания:
// С for-in
do {
for item in collection {
try someThrowingFunction(item)
}
} catch {
handle(error)
}
// С forEach
collection.forEach { item in
do {
try someThrowingFunction(item)
} catch {
// Нужно обрабатывать внутри замыкания
}
}
break или continueПример цепочки:
numbers
.filter { $0 > 1 }
.map { $0 * 2 }
.forEach { print($0) }
Для ссылочных типов (классов) разницы нет, но для значений:
struct Item { var value: Int }
var items = [Item(value: 1), Item(value: 2)]
for item in items {
item.value = 3 // Ошибка: item - let константа
}
items.indices.forEach { items[$0].value = 3 } // Работает
В forEach нужно явно указывать self для захвата:
class MyClass {
func process() {
numbers.forEach { self.handle($0) }
}
}
Основное отличие между for-in и forEach заключается в парадигме (императивный vs функциональный стиль) и возможностях управления потоком. for-in дает больше контроля над выполнением цикла, тогда как forEach лучше интегрируется в цепочки функциональных операций. Выбор между ними должен основываться на конкретных требованиях кода, а не на личных предпочтениях.