본문 바로가기
iOS/Swift배우기

[Swift] Generic이란

by 붕어사랑 티스토리 2024. 3. 20.
반응형

1. Generic Function

 

아래와 같은 함수를 보자. 인트 변수를 두개바꿔주는 함수이다.

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

 

 

만약 정수형이 아니라 실수형을 바꿔주고 싶다면?

 

아래처럼 함수바디 구현체는 같은데 함수이름과 파라미터 자료형만 다른걸 세개나 정의해줘야 한다.

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

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
}

 

 

이는 제네릭으로 해결 가능하다. 자바의 제네릭, c++의 템플릿과 같은것이다.

 

  • 여기서 T는 타입 파라미터 라고 불린다.
  • 함수이름 뒤에 <타입파라미터> 를 붙여주어야 한다.
  • 타입 파라미터는 T가 아닌 다른 이름을 사용할 수도 있다
  • Dictionary<Key, Value> 처럼 여러개의 타입 파라미터를 가질 수 있다.
func swapTwoValues<T>(_ a: inout T, _ b: inout T) {
    let temporaryA = a
    a = b
    b = temporaryA
}

 

 

 

 

2. Generic Type

 

제네릭은 함수뿐만 아니라 타입에도 사용하능하다. 무슨말이냐 하면, struct, class, enumeration에도 사용 가능하다

 

아래는 Int 스택을 나타내는 코드이다. 

struct IntStack {
    var items: [Int] = []
    mutating func push(_ item: Int) {
        items.append(item)
    }
    mutating func pop() -> Int {
        return items.removeLast()
    }
}

 

이는 앞서 본 문제상황처럼 똑같은 문제를 야기한다. double에 필요한 스택을 만든다면 똑같이 중복된 코드를 한번 더 작성해야된다.

 

이는 제네릭으로 또다시 해결 가능하다

 

struct Stack<Element> {
    var items: [Element] = []
    mutating func push(_ item: Element) {
        items.append(item)
    }
    mutating func pop() -> Element {
        return items.removeLast()
    }
}

 

 

 

3. extension과 Genenric

제네릭 타입을 extension할 때는 아래처럼 타입 파라미터를 따로 명시해주지 않아도 사용이 가능하다

 

extension Stack {
    var topItem: Element? {
        return items.isEmpty ? nil : items[items.count - 1]
    }
}

if let topItem = stackOfStrings.topItem {
    print("The top item on the stack is \(topItem).")
}
// Prints "The top item on the stack is tres."

 

 

 

4. Type 제한

아래처럼 타입 파라미터를 특정한 타입형으로 제한할 수 있다.

 

타입파라미터 옆에 : 세미콜론으로 구분하여 클래스나 프로토콜을 붙이면 된다.

func someFunction<T: SomeClass, U: SomeProtocol>(someT: T, someU: U) {
    // function body goes here
}

 

 

 

5. Associated Type과 Generic

프로토콜에서 Associated Type을 이용하면 정해지지 않은 타입에 대해 제한을 걸 수 있다.

 

 

아래 예제의 경우 Item이라는게 일단 뭔지는 모르지만, Item이라고 써진 애들은 다같이 같은 타입을 사용해야 한다.

protocol Container {
    associatedtype Item
    mutating func append(_ item: Item)
    var count: Int { get }
    subscript(i: Int) -> Item { get }
}

 

아래는 구현한 예제이다. typealias로 Item이 Int라고 명시적으로 지정해주고 있다.

struct IntStack: Container {
	// original IntStack implementation
    var items: [Int] = []
    mutating func push(_ item: Int) {
        items.append(item)
    }
    mutating func pop() -> Int {
        return items.removeLast()
    }
    
    // conformance to the Container protocol
    typealias Item = Int
    mutating func append(_ item: Int) {
        self.push(item)
    }
    var count: Int {
        return items.count
    }
    subscript(i: Int) -> Int {
        return items[i]
    }
}

 

 

허나 스위프트는 타입추론이 가능하기에, 대충 규격만 잘 맞췄으면 typealias를 생략 가능하다.

 

이러한 Associated Type에는 Generic도 사용이 가능하다!

struct Stack<Element>: Container {
    // original Stack<Element> implementation
    var items: [Element] = []
    mutating func push(_ item: Element) {
        items.append(item)
    }
    mutating func pop() -> Element {
        return items.removeLast()
    }
    // conformance to the Container protocol
    mutating func append(_ item: Element) {
        self.push(item)
    }
    var count: Int {
        return items.count
    }
    subscript(i: Int) -> Element {
        return items[i]
    }
}

 

또 associatedtype은 아래처럼 타입제한도 가능하다

 

protocol Container {
    associatedtype Item: Equatable
    mutating func append(_ item: Item)
    var count: Int { get }
    subscript(i: Int) -> Item { get }
}

 

반응형

'iOS > Swift배우기' 카테고리의 다른 글

[Swift] PropertyWrapper 사용법  (0) 2024.03.22
[SwiftUI] 자식에게 State 전달하기  (0) 2024.03.21
SwiftUI에서 {} 동작 원리  (0) 2024.03.20
[Swift] inout 파라미터  (0) 2024.03.20
[Swift] Protocol 배우기  (0) 2024.03.19

댓글