🔥 함수 타입

772자
9분

Swift에서 모든 함수는 특정한 함수 타입을 가지고 있습니다. 함수 타입은 함수의 매개변수 타입과 반환 타입으로 구성됩니다.

예를 들어, 다음과 같은 두 개의 간단한 수학 함수가 있다고 해볼까요?

func addTwoInts(_ a: Int, _ b: Int) -> Int {
    return a + b
}
 
func multiplyTwoInts(_ a: Int, _ b: Int) -> Int {
    return a * b
}
swift

addTwoInts 함수와 multiplyTwoInts 함수는 각각 두 개의 Int 값을 받아서, 적절한 수학 연산을 수행한 결과인 Int 값을 반환하죠.

이 두 함수의 타입은 (Int, Int) -> Int입니다. 이는 다음과 같이 읽을 수 있습니다:

"두 개의 Int 타입 매개변수를 가지고, Int 타입 값을 반환하는 함수"

매개변수와 반환 값이 없는 함수도 살펴볼게요:

func printHelloWorld() {
    print("hello, world")
}
swift

이 함수의 타입은 () -> Void이죠. 즉, "매개변수가 없고, Void를 반환하는 함수"라고 할 수 있겠네요.

함수 타입 사용하기

Swift에서 함수 타입은 다른 타입과 마찬가지로 사용할 수 있습니다. 예를 들어, 상수나 변수를 함수 타입으로 정의하고 적절한 함수를 해당 변수에 할당할 수 있죠:

var mathFunction: (Int, Int) -> Int = addTwoInts
swift

이는 다음과 같이 읽을 수 있어요:

"mathFunction이라는 변수를 정의하는데, 이 변수는 '두 개의 Int 값을 받아서 Int 값을 반환하는 함수' 타입이다. 이 새로운 변수가 addTwoInts 함수를 참조하도록 설정한다."

addTwoInts(_:_:) 함수는 mathFunction 변수와 동일한 타입을 가지므로, 이 할당은 Swift의 타입 검사기에 의해 허용됩니다.

이제 mathFunction 이름으로 할당된 함수를 호출할 수 있습니다:

print("Result: \(mathFunction(2, 3))")
// "Result: 5" 출력
swift

동일한 매칭 타입을 가진 다른 함수를 같은 변수에 할당할 수도 있죠. 이는 함수가 아닌 타입에서와 동일한 방식으로 동작합니다:

mathFunction = multiplyTwoInts
print("Result: \(mathFunction(2, 3))")
// "Result: 6" 출력
swift

다른 타입과 마찬가지로, 함수를 상수나 변수에 할당할 때 Swift가 함수 타입을 유추하도록 할 수도 있습니다:

let anotherMathFunction = addTwoInts
// anotherMathFunction은 (Int, Int) -> Int 타입으로 유추됨
swift

함수 타입을 매개변수 타입으로 사용하기

(Int, Int) -> Int와 같은 함수 타입을 다른 함수의 매개변수 타입으로 사용할 수 있습니다. 이를 통해 함수 호출 시 함수의 구현 일부를 호출자가 제공하도록 할 수 있죠.

위의 수학 함수 결과를 출력하는 예제를 살펴볼까요?

func printMathResult(_ mathFunction: (Int, Int) -> Int, _ a: Int, _ b: Int) {
    print("Result: \(mathFunction(a, b))")
}
 
printMathResult(addTwoInts, 3, 5)
// "Result: 8" 출력
swift

이 예제는 printMathResult(_:_:_:)라는 함수를 정의하는데, 이 함수는 세 개의 매개변수를 가집니다. 첫 번째 매개변수는 mathFunction이라고 하며, (Int, Int) -> Int 타입입니다. 이 첫 번째 매개변수에 해당 타입의 모든 함수를 인자로 전달할 수 있죠. 두 번째와 세 번째 매개변수는 ab라고 하며, 둘 다 Int 타입입니다. 이들은 제공된 수학 함수에 대한 두 개의 입력 값으로 사용됩니다.

printMathResult(_:_:_:)가 호출되면, addTwoInts(_:_:) 함수와 정수 값 35가 전달됩니다. 그리고 제공된 함수를 값 35로 호출하고, 결과 8을 출력하죠.

printMathResult(_:_:_:)의 역할은 적절한 타입의 수학 함수 호출 결과를 출력하는 것입니다. 해당 함수의 실제 구현이 어떻게 되는지는 중요하지 않아요. 단지 함수가 올바른 타입이라는 것만 중요하죠. 이를 통해 printMathResult(_:_:_:)는 타입 안전한 방식으로 함수의 일부 기능을 함수 호출자에게 넘길 수 있습니다.

함수 타입을 반환 타입으로 사용하기 (Function Types as Return Types)

함수 타입을 다른 함수의 반환 타입으로 사용할 수도 있습니다. 이를 위해서는 반환하는 함수의 반환 화살표(->) 바로 뒤에 전체 함수 타입을 작성하면 됩니다.

다음 예제는 stepForward(_:)stepBackward(_:)라는 두 개의 간단한 함수를 정의합니다. stepForward(_:) 함수는 입력 값보다 1 큰 값을 반환하고, stepBackward(_:) 함수는 입력 값보다 1 작은 값을 반환하죠. 두 함수 모두 (Int) -> Int 타입을 가집니다:

func stepForward(_ input: Int) -> Int {
    return input + 1
}
 
func stepBackward(_ input: Int) -> Int {
    return input - 1
}
swift

다음은 chooseStepFunction(backward:)이라는 함수인데, 이 함수의 반환 타입은 (Int) -> Int입니다. chooseStepFunction(backward:) 함수는 backward라는 Bool 매개변수에 따라 stepForward(_:) 함수 또는 stepBackward(_:) 함수를 반환합니다:

func chooseStepFunction(backward: Bool) -> (Int) -> Int {
    return backward ? stepBackward : stepForward
}
swift

이제 chooseStepFunction(backward:)을 사용하여 한 방향 또는 다른 방향으로 이동하는 함수를 얻을 수 있습니다:

var currentValue = 3
let moveNearerToZero = chooseStepFunction(backward: currentValue > 0)
// moveNearerToZero는 이제 stepBackward() 함수를 참조함
swift

위의 예제는 currentValue라는 변수를 점진적으로 0에 가깝게 이동시키기 위해 양의 단계 또는 음의 단계가 필요한지 결정합니다. currentValue의 초기 값은 3이므로, currentValue > 0true를 반환하고, 이로 인해 chooseStepFunction(backward:)stepBackward(_:) 함수를 반환하죠. 반환된 함수에 대한 참조는 moveNearerToZero라는 상수에 저장됩니다.

이제 moveNearerToZero가 올바른 함수를 참조하므로, 이를 사용하여 0까지 셀 수 있습니다:

print("Counting to zero:")
// "Counting to zero:" 출력
 
while currentValue != 0 {
    print("\(currentValue)... ")
    currentValue = moveNearerToZero(currentValue)
}
 
print("zero!")
// 3...
// 2...
// 1...
// "zero!" 출력
swift

이처럼 Swift에서는 함수 타입을 다양한 방식으로 활용할 수 있습니다. 함수를 변수나 상수에 할당하고, 함수의 매개변수로 전달하며, 함수에서 함수를 반환할 수도 있죠. 이를 통해 코드의 유연성과 재사용성을 높일 수 있습니다.

함수 타입에 대해 더 자세히 알아보니 흥미롭지 않나요? 함수형 프로그래밍의 핵심 개념 중 하나인 '일급 함수(first-class function)'를 Swift에서도 지원한다는 것을 알 수 있었어요. 함수를 값처럼 다룰 수 있다는 것은 정말 강력한 기능이라고 생각합니다.