Generics - Generic Functions
Generics
제네릭 코드(Generic code)를 사용하면 정의한 요구 사항에 따라 모든 유형에서 동작할 수 있는 유연하고 재사용 가능한 함수 및 타입을 작성할 수 있습니다.
중복을 피하고 의도를 명확하고 추상적으로 표현하는 코드를 작성할 수 있습니다.
제네릭은 Swift의 가장 강력한 기능 중 하나이며 Swift 표준 라이브러리의 대부분은 제네릭 코드로 구축됩니다.
사실 Language Guide 전체에 걸쳐서 제네릭을 사용하고 있습니다.
예를 들어 Swift의 Array나 Dictionary 타입은 모드 제네릭 컬렉션입니다.
Int 값을 보유하는 배열이나 String 값을 보유하는 배열 또는 Swift의 다른 타입의 배열을 만들 수 있습니다.
마찬가지로 특정한 타입의 값을 저장하는 Dictionary도 만들 수 있고 해당 타입이 될 수 있는 항목에는 제한이 없습니다.
The Problem That Generics Solve
제네릭을 이용해서 해결할 수 있는 문제에 대한 예제를 봅시다.
먼저 두개의 Int를 서로 바꾸는 함수입니다.
in-out 파라미터를 사용했고 Int 타입 값 두개를 바꿀 수 있습니다.
위 예제 함수를 통해서 Int 타입 2개를 바꾸는데는 성공했지만 만약에 String, Double 등 추가로 다른 타입의 값도 바꾸고 싶으면 매번 함수를 만들어야 합니다.
swapToInts(::), swapToStrings(::), swapToDoubles(::) 는 동일한 본문을 가지고 있고 파라미터로 전달되는 타입만 다릅니다.
제네릭을 이용하면 하나의 함수로 모든 타입의 값 2개를 바꿀 수 있습니다.
Note
위 3개의 함수의 inout 파라미터 a, b는 서로 타입이 같아야 합니다. a와 b가 같은 타입이 아니라면 바꾸는 것은 불가능합니다. Swift는 type-safe 언어이기 때문에 서로 다른 타입의 변수를 바꾸려고 하면 컴파일 에러가 발생합니다.
Generic Functions
제네릭 함수는 모든 어떤 타입과도 동작할 수 있습니다.
swapTwoInts(:)의 제네릭 버전인 swapTwoValues(:) 함수 입니다.
swapTwoValue(:)의 본문은swapTwoInts(:) 본문과 동일하지만
함수명과 파라미터가 들어가는 첫번째 줄이 차이납니다.
첫번째 줄 끼리 비교를 해보면
제네릭 버전의 함수를 보면 파라미터의 타입이 들어가는 자리에 Int, String, Double 등의 실제 타입이 아닌 “T” 가 들어있는 걸 볼 수 있습니다.
이 임의의 타입 T는 실제로 무엇인지 모르지만 a, b는 같은 타입이어야 합니다.
T의 실제 타입은 swapTwoValues(:) 함수가 호출될 때마다 결정됩니다.
제네릭 함수와 일반 함수의 차이점은 제네릭 함수는 함수의 이름 뒤에 <T> 가 붙습니다.
이 꺽쇠 괄호는 T는 swapTwoValues(:) 함수 내에서 제네릭 타입이라고 Swift에게 설명합니다.
T는 제네릭 타입임으로 Swift는 실제 타입을 찾지 않습니다.
swapTwoValues(:) 함수는 swapTwoInts와 동일한 방식으로 호출하지만 파라미터 두 값이 동일한 타입이기만 하면 어떤 타입이던지 전달할 수 있습니다.
swapTwoValues가 호출될때마다 전달받은 타입으로 부터 제네릭타입이 유추됩니다.
아래 예제에서 제네릭 타입은 Int와 String 타입으로 유추됩니다.
Type Parameters
swapTwoValues(:) 예제에서 임의의 타입 T는 타입 파라미터의 예입니다.
타입 파라미터는 임의의 타입을 지정하고 꺾쇠 괄호 (예: <T>) 사이에 작성하고 함수명 바로 뒤에 작성됩니다.
타입 파라미터를 지정하면 함수의 파라미터 타입을 정의하기 위해 사용하거나 함수의 반환 타입이나 함수의 본문 내에서 타입 주석으로 사용할 수 있습니다. 각각의 경우 타입 파라미터는 함수가 호출될 때마다 실제 타입으로 대체됩니다. (위 예제에서 swapTwoValues(:) 함수는 첫번째 불릴때 Int로 유추되고, 두번째 불릴떄 String으로 유추됩니다.)
콤마로 구분된 꺾쇠 괄호 안에 여러개의 타입 파라미터를 작성하여 하나 이상의 타입 파라미터도 제공 가능합니다.
Naming Type Parameters
대부분의 경우에 타입 파라미터는 타입 파라미터와 제네릭 타입 간의 관계나 함수 관계를 나타내기 위해 Dictionary<Key, Value> 에서 Key와 Value 그리고 Array<Element> 에서 Element와 같이 설명이 포함된 이름이 있습니다.
그러나 의미있는 관계가 없을 때는 위 swapTwoValues(:) 함수 예제에서 T를 사용한 것과 같이 T, U, V 등 단일 문자를 사용하는 것이 일반적입니다.
Note
값이 아니라 타입에 대한 임의의 표시라는 것을 나타내기 위해 항상 타입 파라미터가 주어질 때 대문자 이름 (T와 MyParameter 처럼)으로 주어집니다.