제너릭 코드 (Generic code) 는 정의한 요구사항에 따라 모든 타입에서 동작할 수 있는 유연하고 재사용 가능한 함수와 타입을 작성할 수 있습니다. 중복을 피하고 명확하고 추상적인 방식으로 의도를 표현하는 코드를 작성할 수 있습니다.
제너릭은 Swift의 강력한 특징 중 하나이고 Swift 표준 라이브러리 대부분은 제너릭 코드로 되어 있습니다. 사실 모르고 있더라도 Language Guide 전체에서 제너릭을 사용합니다. 예를 들어 Swift의 Array 와 Dictionary 타입은 둘다 제너릭 콜렉션 입니다. Int 값을 가진 배열, 또는 String 값을 가진 배열 또는 실제로 Swift에서 생성될 수 있는 다른 모든 타입에 대한 배열을 생성할 수 있습니다. 마찬가지로 모든 지정된 타입의 값을 저장하기 위한 딕져너리를 생성할 수 있고 해당 타입에 대한 제한은 없습니다.
::: 설명과 같이 Generics는 모든 타입에 대하여 동작할 수 있습니다. 타입은 Int, String, Bool, Float 등등 많습니다. 그런데 이러한 타입에서 모두 동작할 수 있는 함수와 타입을 작성할 수 있다고 하는군요. (그럼 그냥 모든 변수, 상수 그리고 함수에 대해서 Generics를 사용한다면? 편한거 아닌가?라는 의문이 들었는데 나중에 찾아보도록 합니다.)
아래는 대표적으로 Generics을 왜 사용하는지? 함수에서 활용하는 법을 보여줍니다. :::
제너릭이 해결하는 문제(The problem that Generics solve)
아래와 같이 두개의 Int 값을 입력으로 받아서 값을 바꾸는 표준 함수 swapTwoInts(_:_:)이 있습니다.
함수를 만들고 someInt = 3과 anotherInt = 107을 넣어서 호출했는데 결과적으로 someInt = 107, anotherInt = 3이 된 것을 볼 수 있습니다. (함수에 대한 설명은 함수를 주제로 따로 작성하는 것이 좋을 것 같네요. 지금은 그저 값을 넣었는데 그 값으로 계산을 해서 출력을 내는 기능을 갖는 어떤 것이라고만 기억하셔도 좋을 것 같습니다.)
위의 swapTwoValues(_:_:) 예제에서 임의의 타입 T 는 타입 파라미터 (type parameter) 의 예입니다. 타입 파라미터는 임의의 타입을 지정하고 이름을 지정하며 꺾쇠 괄호 (예: <T>) 사이에 기록하고 함수의 이름 바로 뒤에 작성됩니다.
타입 파라미터를 지정하면 함수의 파라미터 (swapTwoValues(_:_:) 함수의 a 와 b 와 같이) 의 타입을 정의하기 위해 사용하거나 함수의 반환 타입이나 함수의 바디내에 타입 주석으로 사용할 수 있습니다. 각각의 경우 타입 파라미터는 함수가 호출될 때마다 실제 타입으로 대체됩니다 (위의 예 swapTwoValues(_:_:) 에서 T 는 첫번째 함수가 호출될 때 Int 로 대체되고 두번째 호출될 때 String 으로 대체됩니다).
콤마로 구분된 꺾쇠 괄호 안에 여러개 타입 파라미터를 작성하여 하나 이상의 타입 파라미터를 제공할 수 있습니다.
::: 제너릭 함수를 만들기 위해서 함수명 뒤에 <T>와 같이 지정해주는 것을 타입 파라미터라고 부른다고 합니다. 그리고 타입 파라미터는 <U>, <V> 같은 것도 있다고 하는데요. Swift를 갓 배우는 입장에서는 아직 타입 파라미터에 대해서 깊게 사용할 일이 잘 없어서 ...(사실 저도 만나본적이 아직 없어서) 다른 개념들에 대해 더 알아보고 시간나면 들여다보도록 하겠습니다. Generic을 설명한 이유는 콜렉션 타입 중에 Array와 Dictionary 타입이 제너릭 콜렉션이라고 하길래 궁금해서 찾아본 것이며... 설명에 의하면 모든 타입이 사용 가능한 것을 의미하는게 되겠네요~ :) :::
참고한 글
테디호프 드림




덧글