스위프트 함수는 어떤 타입? 클로져랑 사귈려면 타입을 잘 알아야 한다.

함수는 타입이 있다. 섹시한 타입, 청순한 타입…모든 건 타입이 있다. 그러한 타입으로 구별도 하고 같은 부류로 묶기도 한다.

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

위에 정의한 두개의 함수를 보자 하나는 두개의 정수를 더해서 리턴하는 함수이고 다른 하나는 곱한값을 리턴하는 함수이다.
우리는 두개의 함수를 (Int, Int) -> Int 이런 타입을 이해한다.
즉, 두개의 정수를 받아서 하나의 정수를 리턴하는 타입이다.

func printHelloWorld() {
println("hello, world")
}

여기 또 다른 함수가 있다. 입력 파라미터가 없고 리턴도 없다. 그냥 프린트 달랑 하나하고 끝난다.
결국 이 녀석은 () -> () 이렇게 이해한다. 즉 입력없고 리턴도 없다.

스위프트에서 함수는 데이타 타입이다. 즉 정수, 실수, 문자형처럼 그냥 데이타 타입이다.
그러니 타입을 나타내는 String, Int 등이 올 자리에 함수도 타입처럼 올수 있다.


var welcomeMessage: String = "Hello"
var someInt: Int = 3
var mathFunction: (Int, Int) -> Int = addTwoInts

즉 위에 있는 코드의 예처럼 String, Int 타입처럼 (Int, Int) -> Int 이 올 수 있다. 즉
mathFunction 이라는 변수의 이름은 정수 두개를 받아서 결과값으로 정수형을 리턴하는 어떤 함수라도 설정할 수 있다는것이다. 여기에서는 그래서 두개의 정수를 더하는 함수를 mathFunction 으로 설정했다.

물론 mathFunction 에 multiplyTwoInts를 설정할 수도 있다.

결국 mathFunction은 두개의 정수를 받아서 정수를 리턴하는 어떠한 함수와도 잘 맞는다. 매우 융통성이 있고 어떤 할수라도 처리를 할 수 있으니 개발할 때 정해지지 않는 어떤 작업을 실행할때 적절하게 선택되게 할 수 있다.
객체 지향 프로그래밍 개념에서 다형성이라는 개념인데 매우 유용하다.

프로젝트의 소스를 아래 코드로 수정해보자

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

override func viewDidLoad() {
super.viewDidLoad()

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

println(“addTwoInts: \(mathFunction(2, 3))”)
mathFunction = multiplyTwoInts
println(“multiplyTwoInts: \(mathFunction(2, 3))”)

}

결국 같은 mathFunction 을 호출하지만 다른 함수를 대입하여 결과값을 얻을 수 있다.

스크린샷 2015-01-27 오후 1.18.55

 

 

 

함수를 데이타 타입으로 이해했음으로 함수를 다른 함수의 파라미터로 전달 할 수도 있다.
어떤 함수가 매우 유연하려면 함수를 호출할때 그 기능을 설정하면 매우 유연해보인다.

두개의 정수를 받아서 어떤 처리를 하고 그 결과를 리턴하는 함수를 파라미터로 받아 결과를 출력하는 함수를 정의해보자. 헐~~ 뭔가 길고 복잡해 보인다. 일단 코드를 보자

func addTwoInts(a: Int, b: Int) -> Int {
return a + b
}
func multiplyTwoInts(a: Int, b: Int) -> Int {
return a * b
}
func printMathResult(mathFunction: (Int, Int) -> Int, a: Int, b: Int) {
println("Result: \(mathFunction(a, b))")
}

override func viewDidLoad() {
super.viewDidLoad()

var mathFunction: (Int, Int) -> Int = addTwoInts
printMathResult(mathFunction, a: 3, b: 5)
mathFunction = multiplyTwoInts
printMathResult(mathFunction, a: 3, b: 5)

}

printMathResult 라는 함수는 (Int, Int) -> Int 타입을 파라미터로 받는다. 즉 두개의 정수를 받아 정수를 리턴하는 함수 타입이다. 그리고 두개의 정수를 받아서 프린트 하는 간단한 함수가 정의된다.

스크린샷 2015-01-27 오후 1.33.41

출력되는 결과를 보면 같은 함수를 호출하지만 설정된 함수가 다른 함수이므로 다른 결과를 나타낸다.
실질적인 게임등 프로그래밍에 있어 매우 유용한 함수가 만들어 질 수 있다.

 

 

 

이제 함수의 리턴값으로 함수가 리턴되는 경우를 보자.

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

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

override func viewDidLoad() {
super.viewDidLoad()

var currentValue = 3
let moveNearerToZero = chooseStepFunction(currentValue > 0)

println("Counting to zero:")

while currentValue != 0 {
println("\(currentValue)... ")
currentValue = moveNearerToZero(currentValue)
}
println("zero!")
}

조금 길지만 stepForward 라는 함수는 어떤 정수값을 받으면 하나 더해서 리턴하는 함수다. stepBackward 는 반대로 하나 적은 값을 돌려준다. chooseStepFunction 은 참이나 거짓을 받아서 참이면 stepBackward 를 거짓이면 stepForward를 돌려준다. 즉 (Int) -> Int 타입의 함수를 돌려준다.
위에서 정의한 stepForward 와 stepBackward는 둘다 (Int) -> Int 타입이다 따라서 두 함수중에 하나를 리턴하면 된다.

결과적으로 0보다 큰값이 오면 참이되고 stepBackward가 선택된다. moveNearerToZero 함수는 stepBackward 함수가 되고 현재 값이 하나 줄어들어서 설정된 후 다시 while문을 반복한다.

현재 값이 0이되면 루프를 빠져 끝난다.

스크린샷 2015-01-27 오후 1.52.41

댓글 남기기