→ Swift Study

[Swift] forEach, for-in 비교하기

Swift librarian 2025. 4. 29. 19:19

🤔 간단한 실험

아래의 코드를 실행시키면 어떻게 될까?

let numbers = [1,2,3,4,5,6]

numbers.forEach { number in
    if number == 2 { return }
    print(number)
}

당연하게도 2를 제외한 1, 3, 4, 5, 6이 출력될 것이다. 그렇다면 아래의 코드는?

for number in numbers {
    if number == 2 { return }
    print(number)
}

바로바로 아래와 같이 오류가 발생하게 된다.

엇 두개의 정확한 차이가 뭘까?

🧑🏻‍💻 내부 구현

Swift는 오픈소스이기 때문에 내부구현을 찾아볼 수 있었다.

 

swift/stdlib/public/core/Sequence.swift at 376651df4db8d7633874892b685115e2168a7c41 · swiftlang/swift

The Swift Programming Language. Contribute to swiftlang/swift development by creating an account on GitHub.

github.com

  /// Using the `forEach` method is distinct from a `for`-`in` loop in two
  /// important ways:
  ///
  /// 1. You cannot use a `break` or `continue` statement to exit the current
  ///    call of the `body` closure or skip subsequent calls.
  /// 2. Using the `return` statement in the `body` closure will exit only from
  ///    the current call to `body`, not from any outer scope, and won't skip
  ///    subsequent calls.
  ///
  /// - Parameter body: A closure that takes an element of the sequence as a
  ///   parameter.
  @_semantics("sequence.forEach")
  @inlinable
  public func forEach(
    _ body: (Element) throws -> Void
  ) rethrows {
    for element in self {
      try body(element)
    }
  }

결국 코드를 살펴보면 forEach도 내부구현은 for-in으로 되어있는 것을 볼 수 있다. 다만 body: (Element) throws → Void를 실행시킬 뿐이다. 따라서 클로저를 실행시키기 때문에 return을 해도 forEach함수가 종료되는 것이 아닌 forEach안의 body클로저의 실행만 끝나는 것이다.

 

위의 주석에 나와있듯이 breakcontinue같은 loop에서 사용가능한 것들은 쓸 수 없다.

🙅🏻‍♂️ rethrows

rethrows로 되어있기 때문에 body에서 오류를 throw하게 된다면 그것을 다시 던져주기 때문에 아래처럼 try를 붙여줘야 한다.

try numbers.forEach { number in
    if number == 2 {
        throw NumbersError.two(number)
    }
    print("✅ 성공:", number)
}

물론 do-catch를 써준다면 아래처럼 가능하다.

numbers.forEach { number in
    do {
        if number == 2 {
            throw NumbersError.two(number)
        }
        print("✅ 성공:", number)
    } catch {
        print("😵 실패:", error)
    }
}