Swift 제너릭(Generics) - Swift

안녕하세요 테디호프입니다. 
오늘은 제너릭(Generics)에 대해 알아봅니다.
관련 설명이 요녀석은 Swift 공식 홈페이지에 한글로 잘 나와있어서 퍼오기만 한 것 같네요.
공식 홈페이지 예제를 따라 수행해본 것을 남겨봅니다. 


제너릭(Generics)?

제너릭 코드 (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이 된 것을 볼 수 있습니다. (함수에 대한 설명은 함수를 주제로 따로 작성하는 것이 좋을 것 같네요. 지금은 그저 값을 넣었는데 그 값으로 계산을 해서 출력을 내는 기능을 갖는 어떤 것이라고만 기억하셔도 좋을 것 같습니다.)


그리고 비슷한 방식으로 두개의 String 값을 입력으로 받아서 문자열을 서로 바꾸는 표준 함수 swapTwoStrings(_:_:)와 두개의 Double값을 받아서 값을 서로 바꾸는 표준 함수 swapTwoDoubles도 만들어 봅시다. 

 

어 그런데 에러가 나네요? 왜 그럴까요? 이유는 swapTwoStrings(_:_:)는 String 타입을 입력으로 받게 되어 있고 swapTwoDoubles(_:_:)는 Double타입을 받기로 약속하였는데 호출할 때 Int 값이 저장된 someInt, anotherInt로 호출 했기 때문이죠.

그리고 가만 살펴보면 함수에서 입력 타입을 지정하는 것 외에 내부 수행하는 본체는 똑같다는 것을 확인할 수 있습니다.
코드를 작성하다보면 이렇게 반복되는 것을 막 줄이고 싶습니다. (네? 안그렇다구요?)

그럼 어떻게 모든 타입의 값을 받아서 똑같은 동작을 수행하는 함수를 만들어볼 수 있을까요?
네! 지금 우리가 설명하고 있는 것 무엇? Generics로 표준 함수가 아닌 모든 타입을 입력 받을 수 있는 Generic 함수로 해결 할 수 있습니다. 



제너릭 함수(Generic Function)

앞서서 우리는 표준 함수를 통해 Int, String, Double 값을 바꾸려 했습니다. 
자 다음은 제너릭 함수를 통해 모든 타입에 대한 제너릭 함수 swapTwoValue(_:_:)를 만들어 봅니다. 



짜잔, 뭐가 바꼈죠? ... 함수명 뒤에 <T>를 붙임으로써 임의의 타입을 사용하게 되었습니다. T가 무엇을 나타내는 지 알 수 없지만 우리는 a와 b가 모두 같은 타입인 T여야 한다고 말합니다. 그리고 T의 실제 타입은 swapTwoValue(_:_:)가 호출될 때마다 결정이 됩니다. 무슨 말이냐구요? 



짜잔, 이번엔 문자열을 넣었는데 정상적으로 문자열이 서로 바뀐 출력을 볼 수 있습니다. 


짜잔, 이번엔 소수를 넣었는데 정상적으로 소수가 서로 바뀐 출력을 볼 수 있습니다.


짜잔, 이번엔 Bool 타입의 값을 넣었는데 true와 false가 서로 바뀌었습니다.

네 그렇습니다! 제너릭 함수를 만들게 되면 함수에 입력 값이 무엇이냐에 따라서 실제 타입들이 결정됩니다. 
그래서 Int를 넣던~ String을 넣던~ Bool을 넣던 모두 동작할 수 있게 되었죠. 


타입 파라미터(Type Parameters)

위의 swapTwoValues(_:_:) 예제에서 임의의 타입 T 는 타입 파라미터 (type parameter) 의 예입니다. 타입 파라미터는 임의의 타입을 지정하고 이름을 지정하며 꺾쇠 괄호 (예: <T>) 사이에 기록하고 함수의 이름 바로 뒤에 작성됩니다.


타입 파라미터를 지정하면 함수의 파라미터 (swapTwoValues(_:_:) 함수의 a 와 b 와 같이) 의 타입을 정의하기 위해 사용하거나 함수의 반환 타입이나 함수의 바디내에 타입 주석으로 사용할 수 있습니다. 각각의 경우 타입 파라미터는 함수가 호출될 때마다 실제 타입으로 대체됩니다 (위의 예 swapTwoValues(_:_:) 에서 T 는 첫번째 함수가 호출될 때 Int 로 대체되고 두번째 호출될 때 String 으로 대체됩니다).

콤마로 구분된 꺾쇠 괄호 안에 여러개 타입 파라미터를 작성하여 하나 이상의 타입 파라미터를 제공할 수 있습니다.


::: 제너릭 함수를 만들기 위해서 함수명 뒤에 <T>와 같이 지정해주는 것을 타입 파라미터라고 부른다고 합니다. 그리고 타입 파라미터는 <U>, <V> 같은 것도 있다고 하는데요. Swift를 갓 배우는 입장에서는 아직 타입 파라미터에 대해서 깊게 사용할 일이 잘 없어서 ...(사실 저도 만나본적이 아직 없어서) 다른 개념들에 대해 더 알아보고 시간나면 들여다보도록 하겠습니다. Generic을 설명한 이유는 콜렉션 타입 중에 Array와 Dictionary 타입이 제너릭 콜렉션이라고 하길래 궁금해서 찾아본 것이며... 설명에 의하면 모든 타입이 사용 가능한 것을 의미하는게 되겠네요~ :) :::



참고한 글

Swift 공식 홈페이지 - Generics


테디호프 드림







핑백

  • 테디호프의 이글루입니다. : Swift 콜렉션 타입 2021-05-07 16:03:56 #

    ... 것 같아서 나중에 따로 정리를 해봐야겠습니다. 아래표를 보시다가 Hashable, NSClass 그리고 Generic가 무엇인지 모르겠다면밑줄친 부분을 누르면 해당 용어의 설명글로 이동하게 됩니다. 저도 처음엔 저 용어들이 뭔지 몰랐는데 앞서서 개념을 정리해보 ... more

덧글

댓글 입력 영역