티스토리 뷰

Programming/Swift

Swift) 제네릭(Generics)

INSWAG 2019. 8. 28. 12:24

Source : The Swift Programming Language (Swift 5.1 beta)

 

Generics 에 대해 간단히 알아보도록 하겠습니다.

 

  Generic code 는 여러분이 정의한 필요조건에 따라 어떤 타입에서도 작동 가능한 유연하면서도 재사용 가능한 함수와 타입을 작성할 수 있게 해줍니다. 여러분은 중복을 피하고 의도를 명확하고 추상적인 방식으로 표현하는 코드를 작성할 수 있을 겁니다.

 

Generics 는 스위프트의 가장 강력한 기능들 중 하나이며 많은 Swift standard library 가 generic code 로 작성되어 있어요.

사실상 여러분은 제네릭을 사용해 오고 있었어요 다만 알지 못했을 뿐이죠.

 

예를 들어볼까요? 우리는 Array 와 Dictionary 를 스위프트에서 사용하는데, 이 Array Dictionary 의 타입은 우리가 마음대로 지정할 수 있어요. 왜 그럴까요? Array Dictionary 의 세부 구현 내용을 살펴보면 이 친구들은 타입이 제네릭으로 작성되었기 때문에 우리가 타입을 자유롭게 사용해오고 있었던 거에요. 이제 느낌이 좀 오나요?

 

 

 

The Problem That Generics Solve

 

swapTwoInts(_:_:) 라 불리는 제네릭이 아닌 함수가 여기 있어요. 두 Int 값을 서로 스왑하여 값을 바꿔버립니다.

 

  원래 함수의 parameter 는 상수로 선언되기 때문에 두 값을 바꿀 수가 없어요. 그런데, 이걸 가능하게 해주는게 바로 'inout' 키워드 입니다. 이를 이용해 두 값을 바꿀 수가 있어요.

 

inout 키워드를 사용한 펑션에 값을 사용할 때는 앞에 '&' 를 붙여줍니다.

swapTwoInts(_:_:) 함수는 유용하지만 단점이 있어요. 바로 Int 타입의 값만 처리할 수 있다는 거에요.

이를 해결하기 위해 swapTwoStrings, swapTwoDoubles 와 같은 다른 타입도 처리할 수 있는 펑션을 만들어 보죠.

 

눈치 빠르신 분들은 아마 알아차렸겠지만, 세 함수의 몸통 부분을 보세요. 완전 똑같아요. 오직 차이는 '타입' 에 있을 뿐이죠.

와... 너무 비효율적인것 같아요. 이 함수들을 하나로 합칠 방법이 없을까요? 

 

바로 Generic code 가 그러한 함수를 작성하는 것을 가능하게 해줍니다. 굿...

아!!! 제네릭을 이용해 구현한 함수를 보기 전에 주의해야 할 내용이 있어요.

 


주의)

위에서 본 3개의 함수에서 a 와 b 의 타입은 항상 같아야만 해요. 만약 a 와 b 가 같은 타입이 아니면 이 값들을 스왑하는 것은 불가능합니다. 항상 기억해야 할 것은 Swift 는 type-safety 언어라는 것과 타입이 다른 변수들간의 스왑은 허용하지 않는다는 것을요. 시도의 결과는 컴파일 타임 에러일 겁니다.


 

Generic Functions

 

제네릭 함수는 모든 타입과 작동할 수 있어요. 

지금까지 본 함수들의 제네릭 버전인 swapTwoValues(_:_:) 를 볼까요?

 

이 함수의 바디 부분은 맨 처음 살펴본 함수의 바디와 동일해요. 하지만 이 함수의 첫 라인은 약간 달라요. 뭐가 다른지 바로 살펴볼까요?

함수의 제네릭 버전은 실제 타입 이름(Int, String, Double) 대신 'placeholder' 라는 타입 네임을 사용해요(이 경우에는 'T').

placeholder 타입 네임은 T 가 무엇인지에 대한 어떤 것을 말해주지는 않아요. 하지만 이는 a 와 b 가 같은 타입인 T 라는 것을 말해주죠. 이 T가 어떤 타입을 나타내든지 간에요. T의 위치에서 사용될 실제 타입은 이 함수가 불리는 때에 결정된다는 사실이 중요해요.

 

제네릭 함수와 제네릭이 아닌 함수의 다른 차이는 제네릭 함수 이름 옆에 있는 <T> 에요.

'< >' 요 표시는 Swift 에게 T 는  swapTwoValues(_:_:) 함수 정의 안의 placeholder 타입 네임이라는 것을 말해주는 역할을 해요.

왜냐하면 T는 placeholder 이며, Swift 는 T 의 실제 타입에 대해 찾아보려 하지 않거든요.

 

placeholder 가 뭘까요. 음... 쉽게, 자리를 차지하고 있는 친구.

그러니까 '특별한 의미는 없지만 여기는 무언가가 들어올 자리다' 라는 것을 이야기하는 친구 정도로 생각해두면 좋을 것 같아요.

 

swapTwoValues(_:_:) 함수는 이제 swapTwoInts 함수와 같은 방식으로 호출 될 수 있어요.

단, 두 값이 서로 같은 타입인 한 어떤 타입이든 두 개의 값도 전달할 수 있어요.

swapTwoValues(_:_:)가 호출되는 매번 T에 사용할 타입은 함수에 전달된 값의 타입으로부터 추론됩니다.

 

다음 두 개의 예시에서, T 는 Int 와 String 으로 각각 추론됩니다:

cf.

위에서 정의된  swapTwoValues(_:_:) 함수는 swap 이라 불리는 제네릭 함수에서 영감을 받았습니다. 이 함수는 Swift 표준 라이브러리의 한 부분이고 자동적으로 여러분의 앱 내에서 자동으로 사용할 수 있어요. 만약 여러분이  swapTwoValues(_:_:) 함수의 동작이 여러분의 코드에서 필요하다면, 여러분은 Swift 의 swap(_:_:) 펑션을 이용하면 됩니다. 따로 구현하지 않아도 된다는 이야기에요.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

중복을 피하고 의도를 명확하고 추상적 인 방식으로 표현하는 코드를 작성할 수 있습니다.

댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함