Swift Generics와 타입 시스템

  • 이번에는 Swift에서의 Generics에 대해 알아보겠습니다.
  • Generics는 Swift가 타입 시스템이기에 더욱 필요한데요.

Swift 타입 시스템

  • Swift는 타입 시스템을 가진 프로그래밍 언어입니다.
  • 그래서 아래와 같은 코드는 빌드 에러를 리턴합니다.
func sum(a: Int, b: Int) {
  return a + b
}

sum(1,2) // return 3
sum("1", 2) // build error
1 == "1"  // build error

타입 시스템의 장단점

  • 타입 시스템을 가진 언어는 더 안전하고, 버그가 없는 프로그램을 만들 수 있게 해줍니다.
  • 하지만, 다양한 케이스를 일일히 다뤄줘야 한다는 단점도 있는데요.
  • 아래와 같이 두 숫자를 더하는 함수만 봐도 그렇습니다.
func sum(a: Int, b: Int) -> Int {
  return a + b 
}

func sum(a: Double, b: Double) -> Double {
  return a + b
}

func sum(a: CGFloat, b: CGFloat) -> CGFloat {
  return a + b
}

Generic Function

  • 이러한 타입 시스템의 단점을 보완하기 위해 Generics가 존재합니다.
  • Generics를 사용해 만든, 두 숫자를 더하는 아래의 함수를 봅시다.
func sum<T: Summable>(a: T, b: T) -> T {
  return a + b
}
  • 이러한 함수를 "Generic Function"이라고 부릅니다.

Swift Generics

  • Generic Type이라는 것도 있는데요.
  • 애플의 Foundation에서 쓰이는 많은 클래스들도 Generic Type 입니다.
  • Stack 자료 구조로 예를 들어보겠습니다.
struct Stack<Element> {
  var list: [Element] = []
  
  func push(_ element: Element) {
    list.append(element)
  }

  func pop() -> Element {
    return list.popLast()
  } 
}
  • 이런식으로, 초기화 할 때 지정해주는 타입을 Generic Type이라고 하고 Array, Dictionary 등도 이에 속합니다.

Type Constraint

  • Generic의 Type을 제약(Constraint)하기 위해서는 어떤 클래스나 프로토콜을 콜론과 함께 위치시키면 됩니다.
func someFunction<T: SomeClass, U: SomeProtocol>(someT: T, someU: U) {
  // 함수 본문 코드
}

Associated Type

Generic Where 절

  • Generic Where 절(clause)로는 연관 타입이 특정 조건을 준수하도록 할 수 있습니다.
  • 다음 예시에서는 두 컨테이너가 동일한 타입의 컨테이너일 필요는 없지만, 동일한 타입의 아이템들을 가지고 있어야 합니다.
  • 이 조건은 Type Constraint와 Generic Where 절의 조합으로 표현이 가능합니다.
func allItemsMatch<C1: Container, C2: Container>
(_ someContainer: C1, _ anotherContainer: C2) -> Bool
where C1.Item == C2.Item, C1.Item: Equatable {
  // 함수 본문 코드
}

참고