IMCAT.DEV
로그인 가입
Swift 중급 자료구조

Swift 제네릭(Generics) 사용법

Swift 제네릭(Generics) 사용법 — 중급

제네릭(Generics) 사용법

1. 도입 (왜 배워야 하는가)

프로그래밍에서 제네릭(Generics)은 코드의 재사용성과 유연성을 극대화시켜줍니다. 많은 경우, 특정 데이터 타입에 종속되지 않고 다양한 타입을 처리할 수 있는 코드를 작성할 수 있기 때문에 실무에서 매우 유용합니다. 예를 들어, 제네릭을 사용하면 배열, 리스트, 딕셔너리와 같은 자료구조를 만들 때 각기 다른 타입의 데이터를 저장할 수 있습니다.

제네릭을 모르면, 각 데이터 타입에 대해 별도의 코드를 작성해야 하므로 코드가 중복되고 유지보수가 어려워질 수 있습니다. 또한, 타입에 따라 다르게 동작하는 함수를 여러 개 만들어야 하므로 코드의 가독성이 떨어지고, 버그가 발생할 확률이 높아집니다.

2. 핵심 개념 설명

제네릭은 특정 타입에 의존하지 않고 다양한 타입을 처리할 수 있는 기능입니다. 이를 통해 함수, 구조체, 클래스 등을 정의할 때 타입을 매개변수로 받아 사용할 수 있습니다.

실생활 비유

제네릭을 요리 도구에 비유할 수 있습니다. 예를 들어, 모든 종류의 음식을 만들 수 있는 다목적 요리 도구가 있습니다. 이 도구는 특정 음식에만 사용되는 것이 아니라, 다양한 조리법에 맞춰 활용할 수 있습니다. 제네릭도 마찬가지로, 특정 타입에 국한되지 않고 여러 타입에 적용할 수 있는 코드 구조를 제공합니다.

관련 용어 정리

용어설명
제네릭 타입다양한 데이터 타입을 받아들일 수 있는 타입
타입 매개변수제네릭에서 사용되는 타입을 나타내는 변수

3. 기본 코드 예제

아래는 제네릭 함수를 사용하는 가장 기본적인 예제입니다. 두 개의 값을 비교하여 큰 값을 반환하는 함수입니다.

func max<T: Comparable>(a: T, b: T) -> T {
    return a > b ? a : b
}

// 사용 예
let maxInt = max(a: 10, b: 20) // 20
let maxDouble = max(a: 3.5, b: 2.8) // 3.5
let maxString = max(a: "apple", b: "banana") // "banana"

실행 결과

  • maxInt: 20
  • maxDouble: 3.5
  • maxString: "banana"
  • 코드 한 줄씩 동작 설명

    1. func max<T: Comparable>(a: T, b: T) -> T: 제네릭 함수 정의. T는 Comparable 프로토콜을 준수하는 타입을 의미.
    2. return a > b ? a : b: 두 값을 비교하여 큰 값을 반환.
    3. 각 사용 예에서 서로 다른 타입의 값들에 대해 max 함수를 호출하고 결과를 저장.
    4. 4. 실전 활용 예제

      예제 1: 쇼핑몰에서 장바구니를 구현할 때

      struct CartItem<T> {
          var item: T
          var quantity: Int
      }
      
      var item1 = CartItem(item: "사과", quantity: 3)
      var item2 = CartItem(item: 1001, quantity: 2) // 상품 ID

      이 예제에서는 장바구니에 들어갈 수 있는 다양한 타입의 아이템(예: 과일 이름 또는 상품 ID)을 처리할 수 있습니다.

      예제 2: 데이터 처리 함수

      func printElements<T>(elements: [T]) {
          for element in elements {
              print(element)
          }
      }
      
      printElements(elements: [1, 2, 3]) // 정수 배열
      printElements(elements: ["A", "B", "C"]) // 문자열 배열

      이 함수는 어떤 타입의 배열이든 출력할 수 있습니다.

      5. 흔한 실수와 주의사항

    5. 타입 제약을 잊음
    6. - 잘못된 코드:

           func add<T>(a: T, b: T) -> T { return a + b } // T는 + 연산을 지원하지 않음

      - 올바른 코드:

           func add<T: Numeric>(a: T, b: T) -> T { return a + b }
    7. 제네릭 타입을 명확히 하지 않음
    8. - 잘못된 코드:

           func swap(a: Any, b: Any) { ... } // 타입 안전성이 없음

      - 올바른 코드:

           func swap<T>(a: inout T, b: inout T) { ... }

      6. 정리

    9. 제네릭을 사용하면 코드의 재사용성과 유연성을 높일 수 있다.
    10. 다양한 타입을 처리할 수 있는 함수 및 자료구조를 만들 수 있다.
    11. 타입 제약을 통해 안전한 코드를 작성할 수 있다.

다음에 학습하면 좋은 주제는 Associated Types와 Protocol-Oriented Programming입니다. 제네릭과 함께 사용하면 더욱 강력한 타입 시스템을 구축할 수 있습니다.