Хотя оба подхода используются для итерации по коллекциям, между ними есть ключевые различия, которые важно понимать для правильного выбора в разных ситуациях.
let numbers = [1, 2, 3]
for number in numbers {
print(number)
}
numbers.forEach { number in
print(number)
}
for-in
:
break
и continue
return
для выхода из текущей итерации (но не из функции)for number in numbers {
if number == 2 { break } // Прерывает весь цикл
print(number)
}
forEach
:
break
и continue
return
внутри замыкания ведет себя как continue
numbers.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
лучше интегрируется в цепочки функциональных операций. Выбор между ними должен основываться на конкретных требованиях кода, а не на личных предпочтениях.