일급시민의 큰 특징 3가지는 다음과 같다.
즉, 변수, 상수, 그리고 파라미터에 저장하고, 리턴도 할 수 있으려면
Int, Double, String 같은 '자료형'을 가지고 있어야 한다.
그렇다. 함수에도 자료형이 존재 한다.
func sayHello() {
print("Say, Hello")
}
//let f1 = sayHello() // X
// 괄호는 제거하고 함수이름만 할당
// 함수 자체가 저장된다.
let f1 = sayHello
f1() // () -> ()
자료형이 있기 때문에 일급 시민(First Class Citizen)로써
변수나 상수에 저장할 수 있다.
이번 에는 파라미터가 존재하는 함수를 할당해보자.
func printHello(with name: String) {
print("Hello, \(name)!!")
}
let f2: (String) -> () = printHello(with:) // (String) -> ()
let f3 = printHello(with:) // (String) -> ()
상수 f2는 직접 형식을 지정해주고 함수를 할당했고,
f3는 형식추론을 사용했지만 저장된 함수는 동일하다.
f2("friend")
// Hello, friend!!
원래 함수를 호출할 때는 Argument Label를 항상 사용했지만
상수에 저당된 함수를 호출 시에는 Argument Label를 쓰지 않는다.
(Function type 에는 파라미터와 리턴형에 대한 정보만 전달 되기 때문에)
func add(a: Int, b: Int) -> Int {
return a + b
}
var f4: (Int, Int) -> Int = add(a:b:)
f4(1,2) // Argument Label X
// 3
와일드 카드로 숨길 수도 있다.
func add(_ a: Int, with b: Int) -> Int {
return a + b
}
var f4 = add(_:with:)
f4() // Argument Label X
// 3
입출력 함수를 파라미터도 할당 가능하다.
func swapNumbers(_ a: inout Int, _ b: inout Int) {
}
let f5 = swapNumbers(_:_:) // (inout Int, inout Int) -> ()
가변 매개변수를 가지는 경우
func sum(of numbers: Int...) {
}
let f6 = sum(of:) // (Int...) -> ()
func add(_ a: Int, _ b: Int) -> Int {
return a + b
}
func subtract(_ 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
}
4개의 연산하는 함수도 일급시민라는 것을 알면,
호출하고 싶을 때 자료형만 적합하다면
사용자가 원하는 함수를 파라미터에 저장하고 리턴할 수 있다.
함수를 리턴하는 함수를 사용하자.
func selectFunction(from op: String) -> (Int, Int) -> Int {
}
이렇게 정의해주어도 컴퓨터 입장에서는 무리가 없다.
(Int, Int) -> Int 또한 하나의 자료형이기 때문이다.
하지만 함수를 사용하는 사람 입장에서는 당황할 수 있다.
typealias ArithmaticFunction = (Int, Int) -> Int
func selectFunction(from op: String) -> AritmaticFunction? {
switch op {
case "+" :
return func add(_:_:)
case "-":
return func subtracj(_:_:)
case "*":
return func multiply(_:_:)
case "-":
return func divide(_:_:)
default :
return nil
}
}
typealias를 통해 자료형을 미리 지정해놓은다면 함수를 리턴하는 함수라는 것을 쉽게 알 수 있다.
(디폴트의 리턴값은 nil을 전달해주어서 리턴탕입을 옵셔널로 선언했다.)
let af = selectFunction(from: "+")
af?(1,2)
// 3
혹은 이렇게도 가능하다.
selectFunction(from: "*")?(1,2)
// 3