제네릭이란?

우리는 제네릭을 사용하여 더 유연하고 재사용할 수 있는 함수나 타입을 정의하여 사용할 수 있습니다.

정의한 타입, 함수를 선언해서 사용할때 요구되는 파라미터는 어떤 것이든 선택하여 활용할 수 있습니다!(때문에 유연하며 재사용가능)

또한 제네릭을 사용하면 쓸때없이 중복된 코드를 피할 수 있으며 더 명확하고 추상적인 코드를 작성할 수 있습니다.

제네릭은 스위프트에서 가장 강력한 기능중 하나이며 이미 우리는 Array나 Dictionary를 사용하면서 제네릭을 사용하고 있습니다.

예를들어 매번 Array를 사용하지만 그 안의 요소는 [Int], [String], [Double]과 같이 선언한대로 사용할 수 있으며

Dictionary또한 어떠한 타입이든 Value값으로써 사용이 가능합니다.


위의 내용을 예시로 들어 더 이해하기 쉽도록 설명해보겠습니다!



제네릭이 필요한 경우

제네릭을 활용하지 않은 두 파라미터 값을 교환하는 함수 swapTwoInts(::)가 있습니다

func swapTwoInts(_ a: inout Int, _ b: inout Int) {
    let temporaryA = a
    a = b
    b = temporaryA
}

이 함수는 두 파라미터값을 교환하기위해 inout 파라미터를 활용합니다 In-Out Parameter

swapTwoInts(::) 함수는 b의 값을 a에, a의 값을 b에 저장합니다.

var someInt = 3
var anotherInt = 107
swapTwoInts(&someInt, &anotherInt)
print("someInt is now \(someInt), and anotherInt is now \(anotherInt)")
// Prints "someInt is now 107, and anotherInt is now 3"

하지만 이 함수는 두 Int형 파라미터를 교환할수는 있지만

해당 파라미터가 String, Double등 다른 자료형으로 바뀌면 코드를 아래와같이 수정해줘야합니다.

func swapTwoStrings(_ a: inout String, _ b: inout String) {
    let temporaryA = a
    a = b
    b = temporaryA
}

func swapTwoDoubles(_ a: inout Double, _ b: inout Double) {
    let temporaryA = a
    a = b
    b = temporaryA
}

위의 코드는 함수내부에 구현된 코드는 같고 단지 파라미터의 자료형만 다릅니다.

만약 하나의 함수로 파라미터의 자료형만 바꿔주며 사용할 수 있다면 더 유용하고 유연한 코드가될 것입니다.

우리는 바로 제네릭을 통해 이와같이 구현할 수 있습니다!

swift는 같은 자료형에 대해서만 자료교환이 가능합니다. String과 Double자료형과 같이 서로다른 자료형간의 데이터 교환은 불가능하여 컴파일에러를 초래합니다



제네릭함수

제네릭함수는 어떤 타입의 파라미터도 사용할 수 있습니다..

func swapTwoValues<T>(_ a: inout T, _ b: inout T) {
    let temporaryA = a
    a = b
    b = temporaryA
}

함수내의 내용은 swapTwoValues(::)와 swapTwoInts(::)가 동일합니다.

하지만 함수를 정의하는 함수 첫 줄이 다르다는것을 볼 수 있습니다.

func swapTwoInts(_ a: inout Int, _ b: inout Int)
func swapTwoValues<T>(_ a: inout T, _ b: inout T)

제네릭 함수는 정확한 데이터타입명이 아닌 placeholder타입명을 사용합니다.(위 경우는 T)

placeholder타입명은 변수가 정확히 어떤 자료형인지 명시해주고 있지는 않지만 a와 b가 동일한 자료형이라는 것을 말해주고 있습니다.

T의 정확한 자료형은 위 함수가 호출될때 명시되어집니다.

또한 swapTwoValues(::) 에서는 placeholder자료형인 파라미터의 자료형을 <>안에 와 같이 표기해줍니다.

<>안에 사용할 값은 사용자가 임의로 지정해줄 수 있습니다.

함수가 호출될때 어떤타입으로든 전달되는 파라미터의 자료형에따라 T의 자료형이 결정됩니다.

T값이 각각 Int 와 String일 경우 예시입니다.

var someInt = 3
var anotherInt = 107
swapTwoValues(&someInt, &anotherInt)
// someInt is now 107, and anotherInt is now 3

var someString = "hello"
var anotherString = "world"
swapTwoValues(&someString, &anotherString)
// someString is now "world", and anotherString is now "hello"


위의 코드는 두 파라미터의 데이터를 교환하는 함수를 정의한 것입니다. 하지만 이 기능을 가진 함수가 Swift Standard Library안에 이미 존재하기에 두 파라미터의 데이터를 교환하는 기능이 필요할 경우 위와같이 새로정의해줄 필요없이 swap(_:_:)을 호출하여 사용할 수 있습니다.


요약하자면

여러 데이터형을 활용할 수 있는 함수를 정의할때 파리미터에 placeholder자료형을 명시하여 제니릭함수를 정의합니다.
placeholder자료형은 함수를 정의할때 함수명옆에 <>를 통해 명시해줍니다.