Skip to content

Latest commit

 

History

History
121 lines (91 loc) · 8.79 KB

Ch6_advanced1.md

File metadata and controls

121 lines (91 loc) · 8.79 KB

일급 객체로서의 함수와 클로저 다루기

1_함수는 변수에 할당할 수 있어요

지금까지 함수를 여러 번 만들어 보았다. 그런데 스위프트 함수는 더욱 다양한 방식으로 사용되기 때문에 좀 더 자세히 알아보는 것이 필요하다. 먼저 스위프트의 함수는 '일급 객체(First-class Object)'인데, 이런 일급 객체는 다음과 같은 주요 특징을 가진다.

[표] 함수가 일급 객체로서 갖는 주요 특징

제목 설명
변수 할당 변수에 할당할 수 있다.
함수에 파라미터로 전달 함수를 호출할 때 파라미터로 전달할 수 있다.
함수에서 반환 함수에서 반환될 수 있다.

아직 일급 객체라는 말이 잘 이해되지 않을 것이다. 일급 객체는 프로그래밍 언어의 특징 중의 하나이다. 좀 더 쉽게 이해하려면 다른 것보다 우선으로 여기는 중요한 객체라고 생각하면 된다. 한마디로 '중요한 것'이라는 말인데 바로 '함수를 변수에 할당할 수 있다'는 결과로 나타낸다.

함수를 변수에 할당하기

함수를 일급 객체로 다룰 때 가장 중요한 특징은 한마디로 '함수를 변수에 할당할 수 있다!'이다. 앞 장에서 새로운 변수를 만들고 그 변수에 값을 넣는 과정을 할당이라고 하고, = 기호를 사용하면 오른쪽에 있는 값을 왼쪽의 변수에 넣을 수 있다고 하였다. 그런데 이 변수에는 단순히 숫자나 문자열뿐만 아니라 함수도 할당할 수 있다. 즉, = 기호의 오른쪽에 함수가 올 수 있다.

그러면 함수를 변수에 할당하여 사용하는 방법을 알아보겠다. 다음 코드를 입력한다.

func add(first a:Int, second b:Int) -> Int {
    return a + b
}

let result = add(first: 10, second: 10)
print("add 함수를 실행한 결과 : \(result)")

var add2 = add
let result2 = add2(10, 10)
print("add2 변수에 할당된 함수를 실행한 결과 : \(result2)")

출력값) add 함수를 실행한 결과 : 20
      add2 변수에 할당된 함수를 실행한 결과 : 20

add 함수는 더하기 기능을 수행하는 함수로 두 개의 파라미터를 전달 받고 하나의 정수 값을 반환하도록 정의되었다. 이것은 지금까지 여러분이 만들었던 더하기 함수와 다르지 않다. 이렇게 정의한 함수를 호출할 때는 함수 이름 뒤에 소괄호를 붙이고 그 안에 파라미터를 넣어준다. 그런데 add2라는 변수를 선언하면서 함수의 이름인 add를 = 기호 오른쪽에 넣었다. 이렇게 하면 add2 변수에는 add 함수가 할당된다. 그러면 이 함수를 호출할 때는 add라는 이름 이외에도 add2라는 이름을 사용할 수 있다. 함수를 호출할 때 사용할 수 있는 이름이 두 개가 된 것이다. add2는 변수이지만 실제로는 함수를 가리키고 있기 때문에 add2라는 이름 뒤에 소괄호를 붙이면 함수로 실행된다.

add2 변수를 만들고 add라는 이름의 함수를 할당하면 다음 그림처럼 add2 변수가 add 함수를 가리키게 된다. 따라서 함수 이름이 아닌 변수 이름으로 함수를 호출할 수 있게 된다. 바로 이런 점을 주목해야 한다.

그림

변수에 함수가 할당되면 그 변수 상자 안에 함수가 들어 있는 형태가 아니라 변수 상자가 함수를 가리키는 형태가 된다.

참고) 변수 상자 안에 무언가 들어 있는 경우와 변수 상자가 무언가를 가리키는 경우, 뭐가 다를까?

add2 = add
add2 = subtract
변수를 사용하는 일반적인 경우에는 변수 상자 안에 함수가 들어 있다고 생각해도 큰 문제가 생기지 않는다. 그런데 변수
상자가 가리키는 함수를 다른 함수로 변경하려고 할 때는 내부적으로 변수 상자가 함수를 가리킨다는 것을 이해해야 한다.
예를 들어, 다음과 같이 add2 변수에 빼기 함수(subtract)를 할당하면 add2 변수는 빼기 함수를 가리키는 것이 되고
이전에 가리키던 더하기 함수(add)는 메모리에 남아있긴 하지만 더 이상 add2 변수가 가리키지 않는 상태가 된다.

함수를 변수에 할당했으니 함수의 원래 이름으로 호출할 수도 있고, 변수 이름으로 호출할 수도 있다. 이 점을 잘 기억하기 바란다. 왜냐하면 함수를 새로운 변수에 할당하면 함수의 원래 이름이 변수 이름으로 바뀐 것처럼 생각할 수 있기 때문이다. 따라서 함수를 새로운 변수에 할당하는 과정을 몇 번 반복하다 보면 어떤 이름으로 함수를 호출해야 할지 혼동되는 경우가 생기기도 한다.

그러면 함수를 할당할 변수의 자료형은 어떻게 선언해야 할까? 만약 더하기 함수라면 다음과 같은 형태로 선언하게 된다.

function add(a:Int, b:Int) -> Int { ... }

이때 함수 상자의 바깥에서 바라본다면 함수 상자에는 위쪽에 두 개의 구멍, 아래쪽에 하나의 구멍이 있는 형태가 되고 이 구멍의 자료형만 기록하면 다음과 같이 된다.

(Int, Int) -> Int

이것이 함수의 자료형이다. 함수를 변수에 할당하기 전에 변수를 먼저 선언하는 코드를 다음과 같이 추가한다.

func show(data:Int) -> Int {
    return data
}

let show2 : (Int) -> Int = show

let add3 : (Int, Int) -> Int = add

func appendFormFeed(a:Int, b:String) -> (Int, String) {
    return (a+1, b+"\n")
}

let append2 : (Int, String) -> (Int, String) = appendFormFeed
print("append2 호출 결과 : \(append2(10, "김준수"))")

출력값) append2 호출 결과 : (11, "김준수\n")

show 함수에는 Int 자료형의 파라미터가 하나 전달된다 그리고 Int 자료형으로 값을 반환한다. 따라서 show 함수를 할당할 show2 변수의 자료형은 (Int) -> Int로 지정할 수 있다. 그리고 더하기 함수를 할당할 add3 변수의 자료형은 (Int, Int) -> Int가 된다. 만약 함수가 투플을 반환하는 경우에는 -> 기호 뒤에 반환되는 값의 자료형도 (Int, String)과 같은 형태로 명시된다. 코드를 실행해 보면 오류가 발생하지 않는다. 따라서 변수들은 선언하면서 명시한 자료형이 문제가 없고 함수도 정상적으로 할당되었다는 것을 알 수 있다.

그렇다면 함수에 파라미터가 없는 경우와 함수에 반환 값이 없는 경우, 그리고 파라미터와 반환 값이 모두 없는 경우에는 자료형을 어떻게 명시해야 할까? 다음 표는 함수의 유형에 따라 자료형을 어떻게 명시해야 하는지 알려준다.

표

무언가 굉장히 많이 생략된 느낌이다. 스위프트는 코드 실행에 문제가 없다면 조금이라도 코드를 줄일 수 있는 부분은 과감하게 생략한다. 표에서 확인한 세 가지 유형 중에서 파라미터와 반환 값이 모두 없는 경우에는 소괄호가 두 개나 사용되었으니 무슨 수수께끼 같은 기호를 사용한 것 같지만 여기에 사용된 소괄호는 값이 없는 것을 의미하며, 반환 자료형은 Void로 바꿀 수도 있다. Void는 스위프트 내부에서 () 기호와 같은 의미를 갖도록 정의되었다. 즉, 다음과 같이 정의할 수 있다.

typealias Void = ()

타입앨리어스(Typealias)는 이미 알고 있으니 이 코드를 통해 Void와 ()가 동일한 자료형이 되었다는 것을 이해할 수 있을 것이다. 함수의 유형에 따른 자료형 세 가지 경우에서 반환 자료형을 () 대신 Void 키워드로 적용하면 다음과 같은 형태가 된다.

표

사실 함수 이름 뒤에 붙이는 소괄호는 함수를 구별하는 중요한 기호이다. 함수를 정의할 때는 함수 이름과 소괄호, 그리고 중괄호가 있어야 한다. 그리고 함수를 호출할 때는 함수 이름과 소괄호가 있어야 한다. 따라서 함수를 구별할 목적 이외에 소괄호가 다른 용도로 자주 사용되면 코드를 해석할 때 혼동될 수 있다. 따라서 ()보다는 Void 키워드를 사용하는 것이 더 좋을 때가 많다.

Ch6_advanced2.md 파일로 가기

Swift Study Contents로 돌아가기