Generic이란?

  • Generic은 Swift의 가장 강력한 기능 중 하나이며, Generic을 사용하면 재사용 가능하고 유연한 코드를 작성할 수 있다.
  • 뭔말이냐? 바로 예제로 들어갑시다.

Nongeneric

  • Int 형의 두 값을 바꿔주는 함수가 필요하다고 가정하자.
func swapToValue(_ a: inout Int, _ b: inout Int) {
    let tempA = a
    a = b
    b = tempA
}
  • 다 만들었는데, Double 형도, Float 형도, String 형도 바꿔주는걸 만들어달란다.
  • 이런 경우 함수를 복사해서 자료형만 바꾼 똑같은 함수를 몇개나 계속 만들어야 할까?
  • 그래서 Generic이 필요하다.

Generic

func swapToValue<T>(_ a: inout T, _ b: inout T) {
    let tempA = a
    a = b
    b = tempA
}
  • 뭔가 달라진게 있는데 바로 함수명을 쓸때 <T>가 들어간다는 것과 함수안에서도 타입이 T가 된다는 것이다.
  • T가 뭐냐?
  • T는 사실 placeholder라서 아무 글자나 써도 상관이 없다. for-in 구문을을 쓸때 아주 보편적으로 for i in 0...10을 쓸때 i처럼 의례 쓰는 표현이기 때문에 T가 아니어도 된다.
  • 어쨌든 이 말을 특정 자료형에 구애받지 않고 a와 b parameter가 동일한 자료형이라면 그 자료형을 받아들인다는 뜻이라고 보면 쉽다.
  • 이렇게 Generic으로 구현된 함수는 두 parameter의 자료형만 같다면 Int, Float, Double, String 등 다양한 타입에 모두 대응한다.

Type Constraints

  • Type Constraints로 특정 조건을 충족하는 자료형만 받을 수도 있다.
  • 역시 말보단 코드.
func findIndex<T>(of valueToFind: T, in array:[T]) -> Int? {
    for (index, value) in array.enumerated() {
        if value == valueToFind {
            return index
        }
    }
    return nil
}

  • 이 코드를 쓰게 되면 Binary operator '==' cannot be applied to two 'T' operands 라는 에러가 뜬다.
  • 우리가 아는 == 연산자는 서로 같은 값인지 확인하는 연산자인데 왜 못쓰는 것인가?
  • T는 앞서 말했듯 두 자료형이 같으면 들어올 수 있는데, 특정 자료형은 서로 같은 값인지 확인할 수 없는 경우도 있다. (가령 개발자가 정의한 자료형을 떠올려봐라)
  • 같은 값인지 확인할 수 없는 자료형이 들어오게 되면 에러가 나게 되는 것이다.
  • 그래서 이런 경우 간단히 다음 처럼 바꾸기만 하면 된다.
func findIndex<T: Equatable>(of valueToFind: T, in array:[T]) -> Int? {
    for (index, value) in array.enumerated() {
        if value == valueToFind {
            return index
        }
    }
    return nil
}
  • T 옆에 Equatable이 붙었다.
  • Equatableprotocol인데, 이 protocol을 채택하게 되면 같은 값인지 확인할 수 있어야만 하고 할 수 있게 된다. (물론 구현은 개발자 몫이라고는 하나 이마저도 Xcode에서 자동으로 함수를 만들어준다.)
  • 이제 findIndex(of:in:) 함수는 값을 비교할 수 있는 자료형만 들어올 수 있게 된다.
  • 내가 만든 자료형이 parameter로 들어가야 한다면 Equatable을 준수하기만 하면 된다.
  • 추가로 >, <, <=, >= 등의 비교 연산자의 경우는 Comparable을 준수하면 비교할 수 있게 된다.
  • 이상 Generic에 대한 내용을 얉지만 핵심만 짚어봤다.

참고