스위프트와 함수형 프로그래밍
스위프트는 함수형 프로그래밍을 지원하는 프로그래밍 언어이다. 함수형 프로그래밍에서는 함수가 일급객체가 된다. 일급객체란 변수를 뜻한다. 즉, 함수를 기존 변수들처럼 주고 받을 수 있는 것이 바로 함수형 프로그래밍이다. 함수를 변수로 바꿀 수 있으면 코드가 매우 간결해지고 직관적이 된다.
자 그러면 함수형 프로그래밍에서 함수를 어떻게 변수로 주고 받는지를 살펴보자.
우리가 2개의 숫자를 더하거나 곱하는 앱을 만든다고 해보자. 우리가 변수로 함수를 쓰지 못한다고 할 때 다음과 같이 코드를 만들 수 있다.
func calculator(number1: Int, number2: Int, operation: String) -> Int {
switch (operation) {
case "add":
return add(number1: number1,number2: number2)
case "multiply":
return multiply(number1: number1,number2: number2)
default:
return 0
}
}
func add(number1: Int, number2: Int) -> Int {
return number1 + number2
}
func multiply(number1: Int, number2: Int) -> Int {
return number1 * number2
}
변수는 3개가 필요하다. 2개의 숫자와 어떤 operation을 할 것인지에 대한 변수 1개이다. 이에 대해 내부에서는 switch-case문을 이용해 operation에 따라 어떤 동작을 할 것인지를 결정해야 한다.
이는 매우 비효율적이다. 만약 operation 부분에 어떤 동작을 할지를 넣을 수 있다면 굳이 이렇게 할 필요가 없을 것이다. 만약 위의 코드를 함수형 프로그래밍에 맞춰 바꾸면 다음과 같은 코드가 된다.
func calculator(number1: Int, number2: Int, twoNumberOperator: (Int, Int) -> Int) -> Int {
twoNumberOperator(number1,number2)
}
매우 간단하지 않은가? 지금부터 이렇게 바꾸는 방법에 대해 살펴보자.
함수를 변수로 사용하기
함수를 변수로 사용하기 위해서는 변수의 타입이 제공되어야 한다. 형태는 다음과 같다.
([입력 파라미터의 타입1], [입력 파라미터의 타입2]) -> [Return 타입]
만약 2개의 Int를 입력 파라미터로 받아 Int을 Return 한다고 하면 다음과 같이 쓸 수 있다.
(Int, Int) -> Int
이제 단순히 위의 타입을 함수의 인자에 넣으면 된다. Int 두개를 입력 받아 Int를 Return하는 함수를 타입으로 만들면 다음과 같이 표현된다. 아래 코드의 twoNumberOperator의 타입이 바로 함수형 타입이 된다.
func calculator(number1: Int, number2: Int, twoNumberOperator: (Int, Int) -> Int) -> Int {
twoNumberOperator(number1,number2)
}
twoNumberOperator에는 Int 두개를 파라미터로 받고 Int를 return하는 함수가 올 수 있다. 예를 들어 두 숫자를 더하는 다음의 함수가 변수로 들어갈 수 있게 된다.
func add(number1: Int, number2: Int) -> Int {
return number1 + number2
}
이를 변수에 넣는 방법은 간단하다. 단순히 함수명을 인자로 넣어주면 된다.
calculator(number1: 2, number2: 3, twoNumberOperator: add)
위 코드를 수행하면 다음과 같이 결과가 나온다.

Closures 를 변수로 사용하기
하지만 이렇게 하는 것은 매번 변수로 함수를 넣기 위해 변수를 선언해야 한다. 이에 대해 스위프트에서는 클로저(Closures)라 부르는 함수를 변수로 직접 입력할 수 있는 방식을 제공한다. 클로저는 익명함수로 이름이 없는 함수로 그 자체로 변수가 된다.
함수를 클로저로 바꾸는 방법은 간단하다. func키워드와 이름을 지우고 전체를 {}로 감싼 다음 타입 뒤에 in을 붙여 연산부와 선언부를 나누는 방식으로 바꾼다.
{([입력 파라미터의 타입1], [입력 파라미터의 타입2]) -> [Return 타입] in
[연산]
return [Return 값]
}
예를 들어 아래의 함수를 클로저로 바꿔보자.
func add(number1: Int, number2: Int) -> Int {
return number1 + number2
}
클로저로 바꾸면 다음과 같이 표현된다. 클로저는 익명 함수이기 때문에 이름이 없으며(add 제거) 그 자체로 하나의 변수이기 때문에 { }로 감싸진다. 입력값과 리턴값을 구분하기 위해서는 in이라는 값이쓰인다.
{(number1: Int, number2: Int) -> Int in
return number1 + number2
}
이 클로저는 직접 함수가 파라미터로 오는 곳에 변수로 넣을 수 있다.
calculator(number1: 2, number2: 3, twoNumberOperator: {(number1: Int, number2: Int) -> Int in
return number1 + number2
})
만약 위와 같이 클로저가 변수로 들어갈 때는 입력 파라미터의 타입과 리턴 값의 타입이 정해져 있으므로 생략해서 다음과 같이 쓸 수도 있다. '$0' 는 클로저의 첫번째 변수값이고, '$1' 은 클로저의 두번째 변수값이며 {$0+$1} 은 그 자체로 리턴값이 된다.
calculator(number1: 2, number2: 3, twoNumberOperator: {$0 + $1})
'IOS > Swift' 카테고리의 다른 글
[Swift] internal parameter name과 external parameter name (0) | 2021.12.25 |
---|---|
[Swift] JSONDecoder 사용하여 JSON 데이터 파싱하기 (0) | 2021.12.25 |
[Swift] protocol이란 무엇인가? (0) | 2021.12.22 |
[Swift] Struct와 Class의 차이는 무엇인가? (0) | 2021.12.20 |
[Swift] struct 내부에서 변수값 변경하기 (0) | 2021.12.19 |