Swift는 객체지향 + 함수형 + 프로토콜형 프로그래밍이 혼재돼있는데 그 중 함수형 프로그래밍이 가능한 이유는 바로 함수가 1급 객체
이기 때문입니다.
1급 객체
란 무엇일까요? 1급 객체는 3가지 특징이 있습니다.
- 변수나 상수에 함수를 대입할 수 있다.
- 함수의 반환 타입으로 함수를 사용할 수 있다.
- 함수의 인자값으로 함수를 사용할 수 있다.
다음과 같이 주어진 배열 안에 주어진 원소가 존재하는지 판단하여 Bool 타입을 리턴하는 함수가 있습니다.
func checkBankInformation(bank: String) -> Bool {
let bankArray = ["우리", "KB", "신한"]
return bankArray.contains(bank) ? true : false
}
평소에는 함수를 활용할 때 다음과 같이 리턴값을 변수나 상수에 할당하곤 합니다. 하지만 이러한 코드는 함수를 실행한 뒤의 반환값을 할당한 것이지 함수를 대입했다고 볼 수 없습니다! 이때 bankAccount의 타입은 checkBankInformation의 리턴타입인 Bool 타입입니다.
let bankAccount = checkBankInformation(bank: "우리")
이렇게 프로퍼티에 함수의 이름만 작성해주면 함수를 대입할 수 있습니다. 하지만 이 단계에서 함수가 실행되지는 않습니다.
let rinAccount = checkBankInformation
이처럼 함수를 호출해줘야 함수가 실행됩니다.
rinAccoutn("신한")
func currentAccount() -> String {
return "계좌 있음"
}
func noCurrentAccount() -> String {
return "계좌 없음"
}
// 가장 외쪽에 위치한 -> 를 기준으로 오른쪽에 놓인 모든 타입은 반환값을 의미한다.
func checkBank(bank: String) -> (() -> String) {
let bankArray = ["우리", "KB", "신한"]
return bankArray.contains(bank) ? currentAccount : noCurrentAccount
}
checkBank는 문자열을 매개변수로 받은 후 () -> String
타입의 함수를 리턴하는 메서드입니다.
해당 은행이 배열에 있는 경우에는 currentAccount 메서드를 리턴하고 없는 경우에는 noCurrentAccount 메서드를 리턴합니다.
let rin = checkBank(bank: "농협")
rin() // 계좌없음
함수를 리턴받아서 프로퍼티에 대입한 후 해당 프로퍼티 옆에 함수 실행연산자()를 붙여주면 해당 함수를 실행할 수 있습니다.
func plus(a: Int, b: Int) -> Int {
return a + b
}
func minus(a: Int, b: Int) -> Int {
return a - b
}
func multiply(a: Int, b: Int) -> Int {
return a * b
}
func divide(a: Int, b: Int) -> Int {
return a / b
}
func calculate(operand: String) -> (Int, Int) -> Int {
switch operand {
case "+": return plus
case "-": return minus
case "*": return multiply
case "/": return divide
default: return plus
}
}
let result = calculate(operand: "-")(4, 3)
result에 메서드를 대입한 후 그 끝에 매개변수를 담은 함수 실행 연산자를 붙여주면 바로 함수를 실행한 값을 받을 수 있습니다.
이때 콜백 함수로 자주 사용이 됩니다.
콜백 함수란 특정 구문의 실행이 끝나면 시스템이 호출하도록 처리된 함수를 말합니다.