swift로 만든 코드들을 보다보면 for-in문 보다는 고차함수를 활용하여 작성한 경우를 많이 볼 수 있습니다.
처음에 고차함수(forEach, filter, reduce 등등)를 공부하다보면 for-in문으로도 충분히 해결할 수 있는 것들은데 왜 고참함수를 사용할까? 라는 의문을 들었습니다.
for-in문 보다 고차함수를 더 선호해서 사용하는것인지 아니면 관습같은건지 고차함수를 활용한 코드들이 훨씬 더 많았기 때문에 나는 for-in문과 고차함수의 차이점을 알아보았습니다.
반복문의 하나로 프로그램 언어를 공부하게 되면 초반부분에 만날 수 있는 for문과 비슷한 역활을 합니다.
swift의 for-in문은 보통 2가지의 기능을 한다고 생각하면 좋을거 같습니다.
ex)
let array = [1,2,3,4,5]
for i in array {
print(i)
}
//1
//2
//3
//4
//5
고차함수란 다른 함수의 전달인자로 받거나 함수 실행의 결과를 함수로 반환하는 함수를 뜻하고 있습니다.
고차함수는 forEach, filter, reduce, sorted 등등 여러가지 기능을 가지고 있습니다.
그중에서 forEach에 대해서 정의하자면
Calls the given closure on each element in the sequence in the same order as a for-in loop.
각 요소에 대해 지정된 클러저를 통해 for-in문과 동일한 순서로 호출한다고 애플에서는 설명하고 있습니다.
ex)
let array = [1,2,3,4,5]
array.forEach{ i in
print(i)
}
//1
//2
//3
//4
//5
위에서 간단하게 for-in문과 고차함수에 대해서 설명을 해봤습니다.
보신거와 같이 for-in문과 고차함수는 상당히 비슷한 기능을 하는 것을 볼 수 있습니다.
특히 forEach 같은경우에는 애플에서 for-in문과 같은 기능한다고 설명까지 하고 있습니다.
그렇다면 왜 애플은 같은 기능을 하는 문법을 2개나 만들었을까??
한번 알아보겠습니다.
특히 공식문서에는 for-in문과 forEach는 동일한 역활을 하고 있습니다.
실제로 forEach는 for-in문을 활용하여서 사용된다고 나와 있습니다.

또한 apple의 github에서도 볼수 있습니다. (깃허브)
@_inlineable
public func forEach(
_ body: (Element) throws -> Void
) rethrows {
for element in self {
try body(element)
}
}
다행이도 차이점에 대해서 애플은 공식문서에서 친절히 설명해주고 있네요
Using the forEach method is distinct from a for-in loop in two important waysn
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.
실행 시간
그렇다면 둘이 같은 기능을 하고 있다면 속도차이는 안나는 것일까?? 한번 실험해보기로 했습니다.
둘을 실행시켰을때 속도 차이가 나는지에 대해서 한번 알아보도록 하겠습니다.

위 코드처럼 1억개의 배열이 있을때 약 0.4초 정도 속도차이가 나는 것을 볼 수있습니다.
이정도의 차이가 나는것은 클로져가 메모리 구조때문에 나오는 차이 일 것이며
그렇게 유의미한 속도차이라고 말할 수 는 없을 것 입니다.
"애플 깃허브 Sequence.swift" 를 보면은 반복문이 필요한 고차함수들은 for-in문과 while문으로 실행한다는 것을 알수 있습니다.
그렇다면은 왜 애플은 클로저로 반복문을 사용하게 만들었을까?? 라고 생각한다면
아마도 그건 코드 가독성때문이라고 말할수 있을것입니다.
가령 예를들어서 각 숫자로된 문자열은 인트형으로 바꾸고 숫자가 5이상 인것들만 모으고 그것을 다 더한 값을 구해야 한다면 어떻게 작성할 수 있을까요?
for-in문으로만 작성한다면
let array = ["1", "4", "8", "2", "11", "-2", "32"]
// 1) 문자열을 인트형으로 변환
var intArray = [Int]()
for i in array {
intArray.append(Int(i)!)
}
// 2) 5이상 인것들만 모으기
var newIntArray = [Int]()
for i in intArray {
if i >= 5 {
newIntArray.append(i)
}
}
// 3) 모은 원소들을 전부 더하기
var sum = 0
for i in newIntArray{
sum += i
}
return sum // 51
하지만 이것을 고차함수로 작성한다면 어떻게 될까요??
let array = ["1", "4", "8", "2", "11", "-2", "32"]
// 1) 문자열을 인트형으로 변환
let intArray = array.map{Int($0)!}
// 2) 5이상 인것들만 모으기
let newIntArray = intArray.filter{$0 >= 5}
// 3) 모은 원소들을 전부 더하기
let sum = newIntArray.reduce(0, +)
return sum // 51
위 코드보다도 더 간결하게 줄일 수도 있습니다.
let array = ["1", "4", "8", "2", "11", "-2", "32"]
let result = array.map{Int($0)!}.filter{$0 >= 5}.reduce(0, +)
return result // 51
심지어 한 줄로도 작성이 가능합니다.
return ["1", "4", "8", "2", "11", "-2", "32"].map{Int($0)!}.filter{$0 >= 5}.reduce(0, +)
위 코드들 처럼 고차함수를 활용한 코드들은 for-in문을 사용한 코드보다 훤씬 더 간결해지고 한결 보기 편해집니다.
또한 다른 사람들이 코드를 볼때도 한눈에 들어오기 때문에 코드를 작성한 사람의 의도를 알기 쉽기때문에 가독성도 좋아졌다고 말할 수 있겠네요
이것처럼 속도에만 집착하기 보다는 고차함수를 사용하여 간결하게 표현한다면 생상성을 높이는데 도움이 될수도 있고 가독성도 높여주어 다른사람들이 코드를 볼 때 이해를 더 빠르게 할게 할 수 있을 것 입니다.
그래서 앞으로는 무작정 실행속도만 빠르다고 좋은코드가 아니고
어떤 코드가 좋은 코드들인지 고려하고 판단해서 좋은 코드를 작성할수 있게 생각하는것이 중요하다고 느껴지는 시간이였습니다.