티스토리 뷰

iOS 개발/Swift

[Swift 3] 제네릭 (Generics)

beankhan 2017. 4. 16. 19:32

출처

http://kka7.tistory.com/28




제네릭


제네릭이 해결하는 문제

func swapTwoInts(_ a: inout Int, _ b: inout Int) {

    let temp = a

    a = b

    b = temp

}


var someInt = 3

var anotherInt = 10

swapTwoInts(&someInt, &anotherInt)




위와 같은 코드를 자료형 별로 모두 만들 필요가 없게해준다.




제네릭 함수


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

    let temp = a

    a = b

    b = temp

}


위 함수는 Int, Double, String 등 모든 자료형에서 사용할 수 있다.




타입 매개변수, 이름짓기

위 swap 예제에서 견본타입 T 는 타입 매개변수 (type parameter) 의 예이다.
하나 이상의 타입 매개변수를 꺾인 괄호 ( < > ) 안에 넣을 때
이름을 콤마 ( , ) 로 구분하도록 한다.

대부분의 경우 타입 매개변수는
Dictionary <Key, Value>
Array <Elements> 처럼 제네릭 타입이나 함수와 관련된 설명이 포함된 이름을 가진다.
하지만 관계가 없을 때는 
전통적으로 " T, U, V " 로 들어간다.




제네릭 타입


아래와 같이 Int 로 정의되어 있는 것을 Element 라는 타입으로 변경할 수 있다.


struct IntStack {

    var items = [Int]()

    mutating func push(_ item: Int) {

        items.append(item)

    }

    mutating func pop() -> Int {

        return items.removeLast()

    }

}



struct Stack<Element> {

    var items = [Element]()

    mutating func push(_ item: Element) {

        items.append(item)

    }

    mutating func pop() -> Element {

        return items.removeLast()

    }

}





타입 제약

타입 제약 지정은 타입 매개변수가 특정 클래스로부터 상속해야하거나
특정 프로토콜이나 프로토콜 구성을 준수해야할 때 사용한다.


예를들어 Dictionary 타입은 Key 로 사용할 수 있는 타입에 제한을 준다.
Key 는 반드시 hashable 해야한다.


func someFunction<T: SomeClass, U: SomeProtocol>(someT: T, someU: U) {

    

}





타입 제약 동작

String 배열에서 같은 String 을 찾아 index 를 반환하는 메소드이다.

func findIndex(ofString valueToFind: String, in array: [String]) -> Int? {

    for (index, value) in array.enumerated() {

        if value == valueToFind {

            return index

        }

    }

    return nil

}


위 코드를 제네릭으로 변경하기위해 아래처럼 작성하면 complie error 가 난다.




func findIndex<T>(ofString valueToFind: T, in array: [T]) -> Int? {

    for (index, value) in array.enumerated() {

        if value == valueToFind {

            return index

        }

    }

    return nil

}



그 이유는 Swift 의 모든 타입이 동등연산자 ( == ) 로 비교되는 것이 아니기 때문에

value == valueToFInd 를 추측할 수 없다.

동등연산자로 비교하기 위해 타입을 제약한다.


func findIndex<T: Equatable>(ofString valueToFind: T, in array: [T]) -> Int? {

    for (index, value) in array.enumerated() {

        if value == valueToFind {

            return index

        }

    }

    return nil

}







연관된 타입

연관된 타입은 프로토콜에서 사용되는 타입의 견본 (placeholder) 이름을 준다.
associatedtype 키워드로 구현가능하다.


연관 타입 동작

예제로 stack 에 적용될 프로토콜을 이용한다.
아래 Container 에서 Item 은 연관 타입으로 
Container Protocol 안에서 제네릭처럼 사용된다.


protocol Container {

    associatedtype Item

    mutating func append(_ item: Item)

    var count: Int { get }

    subscript(i: Int) -> Item { get }

}


struct Stack<Element>: Container {

    var items = [Element]()

    mutating func push(_ item: Element) {

        items.append(item)

    }

    mutating func pop() -> Element {

        return items.removeLast()

    }

    //MARK: Container

    mutating func append(_ item: Element) {

        push(item)

    }

    var count: Int {

        return items.count

    }

    subscript(i: Int) -> Element {

        return items[i]

    }

}






제네릭 Where 절

타입 제약은 제네릭 함수나 타입과 연관된 타입 매개변수에 대한 요구사항을 정의했었다.

또한 연관된 타입에 대한 요구사항을 정의할 수도 있는데
제네릭 Where 절로 이용할 수 있다.

func allItemsMatch<C1: Container, C2: Container>(_ item1: C1, _ item2: C2) -> Bool

    where C1.Item == C2.Item, C1.Item: Equatable {

        

        if item1.count != item2.count {

            return false

        }

        

        for i in 0..<item1.count {

            if item1[i] != item2[i] {

                return false

            }

        }

        return true

}




제네릭 where 절이 있는 확장


extension Stack where Element: Equatable {

    func isTop(_ item: Element) -> Bool {

        guard let topItem = items.last else {

            return false

        }

        return topItem == item

    }

}


만약 요소들이 equatable 하지 않은 Stack 에서 isTop method 를 호출하면

compile 에러가 발생한다.



extension Container where Item: Equatable {

    func startsWith(_ item: Item) -> Bool {

        return count >= 1 && self[0] == item

    }

}









































공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함