[Swift🦩] #23 Generic ⭐️⭐️

λ˜μƒΒ·2022λ…„ 4μ›” 22일
0

iOS

λͺ©λ‘ 보기
35/42
post-thumbnail
  • λͺ¨λ“  νƒ€μž…μ—μ„œ λ™μž‘ν•˜λŠ” μœ μ—°ν•œ ν•¨μˆ˜, νƒ€μž…μ„ μž‘μ„±ν•  수 μžˆλ‹€.
  • μ€‘λ³΅λ˜λŠ” μ½”λ“œλ₯Ό ν”Όν•˜κΈ° μœ„ν•΄μ„œ μž‘μ„±
  • νƒ€μž…μ„ 좔상화 ν•œλ‹€κ³  보면됨.

1. μ œλ„ˆλ¦­μ΄ ν•΄κ²°ν•˜λŠ” 문제

  • μ•„λž˜μ˜ μ„Έ ν•¨μˆ˜λŠ” 같은 역할을 ν•˜μ§€λ§Œ, input νƒ€μž… λ•Œλ¬Έμ— λ‹€ λ”°λ‘œ 씀.
  • μ—¬κΈ°μ—μ„œ μ€‘μš”ν•œ 것은 a, b 인자의 νƒ€μž…μ΄ λͺ¨λ‘ κ°™λ‹€λŠ” 것.
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
}

2. Generic Function

  • T λΌλŠ” μž„μ˜μ˜ νƒ€μž… 이름을 μ‚¬μš©ν•΄μ„œ λ‚˜νƒ€λ‚Έλ‹€.
  • a, b κ°€ 무슨 νƒ€μž…μ΄λ“  μ„œλ‘œ 같은 νƒ€μž…μ΄κΈ°λ§Œ ν•˜λ©΄ λ˜λŠ” κ²ƒμž„.
  • μž„μ˜μ˜ νƒ€μž… 이름이라고 <T> 둜 μ „λ‹¬ν•˜λŠ” κ²ƒμž„.
func swapTwoValues<T>(_ a: inout T, _ b: inout T) {
    let temporaryA = a
    a = b
    b = temporaryA
}

+) 사싀 swap 의 경우 이미 μ• ν”Œμ—μ„œ μ œκ³΅ν•˜λ‹ˆκΉŒ κ΅¬ν˜„ν•΄μ„œ 쓰지 말자.


3. Type Parameters

  • μœ„μ˜ T κ°€ νƒ€μž… νŒŒλΌλ―Έν„°μ˜ μ˜ˆμ‹œ.
  • νƒ€μž… νŒŒλΌλ―Έν„°λ₯Ό 지정해두면, ν•¨μˆ˜μ˜ νŒŒλΌλ―Έν„°, λ°˜ν™˜ νƒ€μž…, ν•¨μˆ˜ λ°”λ”” λ‚΄μ—μ„œ νƒ€μž… μ£Όμ„μœΌλ‘œ μ‚¬μš©ν•  수 μžˆλ‹€.

이름

  • 보톡 Dictionary<Key, Value> , Array<Element> 처럼 기본적인 이름이 μ •ν•΄μ Έ μžˆλŠ” κ²½μš°κ°€ 있음.
  • 직접 μ‚¬μš©ν•  λ•ŒλŠ” T U V 같은 단일 문자λ₯Ό μ‚¬μš©ν•΄μ„œ μ§€μ •ν•΄μ£ΌλŠ” 것이 일반적.

4. Generic Types

  • Generic 을 μ΄μš©ν•΄μ„œ ν•¨μˆ˜λ§Œ μ •μ˜ κ°€λŠ₯ν•œ 것이 μ•„λ‹˜.
  • Type 도 μ •μ˜ν•  수 있음.
  • Array Dictionary 처럼 λͺ¨λ“  νƒ€μž…μ—μ„œ λ™μž‘ν•  수 μžˆλŠ” μ‚¬μš©μž μ •μ˜ 클래슀, ꡬ쑰체, μ—΄κ±°ν˜•

μ˜ˆμ‹œ) μŠ€νƒ κ΅¬ν˜„

// λ§Œμ•½ Int 라면 μ΄λŸ°μ‹μœΌλ‘œ μ½”λ“œλ₯Ό 지거닀.
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()
    }
}
  • μ‹€μ œλ‘œ μ‚¬μš©ν•  λ•ŒλŠ” μ–΄λ–€ νƒ€μž…μœΌλ‘œ λ§Œλ“€κ±΄μ§€ λͺ…μ‹œν•΄μ£Όλ©΄ λœλ‹€.
var stackOfStrings = Stack<String>()
stackOfStrings.push("uno")
stackOfStrings.push("dos")
stackOfStrings.push("tres")
stackOfStrings.push("cuatro")
// the stack now contains 4 strings

5. Extenseion in Generic

  • extension 으둜 Generic Type 을 ν™•μž₯ν•  λ•ŒλŠ”, \ λ₯Ό μ“Έ ν•„μš” μ—†λ‹€.
extension Stack {
    var topItem: Element? {
        return items.isEmpty ? nil : items[items.count - 1]
    }
}

6. Type Constraints

  • Generic 을 μ‚¬μš©ν•˜λ©΄ λͺ¨λ“  νƒ€μž…μ— μ‚¬μš©μ΄ κ°€λŠ₯ν•΄μ§€λŠ”λ°,
  • 항상 λͺ¨λ“  νƒ€μž…μ— κ°€λŠ₯ν•˜λ©΄ μ•ˆλ˜λŠ” μˆœκ°„μ΄ 있음.
  • ex) Dictionery<Key, Value> 의 Key: Hashable

νƒ€μž… μ œμ•½ ꡬ문

  • <T: SomeClass, U: SomeProtocol> 처럼 μž„μ˜μ˜ νƒ€μž…μ΄ 따라야 ν•˜λŠ” 것을 뒀에 써주기.
func someFunction<T: SomeClass, U: SomeProtocol>(someT: T, someU: U) {
    // function body goes here
}

νƒ€μž… μ œμ•½ λ™μž‘

// String λ°°μ—΄μ—μ„œ μ„ ν˜•νƒμƒ‰.
func findIndex(ofString valueToFind: String, in array: [String]) -> Int? {
    for (index, value) in array.enumerated() {
        if value == valueToFind {
            return index
        }
    }
    return nil
}
  • String 만이 μ•„λ‹ˆλΌ κ·Έλƒ₯ 전체 λ°°μ—΄μ—μ„œ κ°€λŠ₯ν–ˆμœΌλ©΄ μ’‹κ² μŒ.
  • == 이 μ–΄λ–€ νƒ€μž…μ—μ„œλ‚˜ μ‚¬μš© κ°€λŠ₯ν•œ 것이 μ•„λ‹ˆλ―€λ‘œ T λŠ” Equatable
func findIndex<T: Equatable>(of valueToFind: T, in array:[T]) -> Int? {
    for (index, value) in array.enumerated() {
        if value == valueToFind {
            return index
        }
    }
    return nil
}

7. Associated Values ⭐️⭐️

  • ν”„λ‘œν† μ½œμ„ μ •μ˜ν•  λ•Œ, μ—°κ΄€λœ νƒ€μž…μ„ μ„ μ–Έν•  수 μžˆλ‹€.
  • ν”„λ‘œν† μ½œμ˜ λΆ€λΆ„μœΌλ‘œ μ‚¬μš©λ˜λŠ” νƒ€μž…μ— μž„μ˜μ˜ 이름을 λ„£λŠ”λ‹€.
  • μ‹€μ œ ν”„λ‘œν† μ½œμ΄ μ±„νƒλ˜λ©΄ ν•΄λ‹Ή νƒ€μž…μ΄ 무엇인지 지정됨.

associatedtype

// Item μ΄λΌλŠ” μž„μ˜μ˜ νƒ€μž….
// Item 이 무엇일진 λͺ¨λ₯΄μ§€λ§Œ ν•΄λ‹Ή νƒ€μž…μ„ μ΄μš©ν•΄μ„œ ν”„λ‘œν† μ½œμ„ μ •μ˜ν•  수 있음.
protocol Container {
    associatedtype Item
    mutating func append(_ item: Item)
    var count: Int { get }
    subscript(i: Int) -> Item { get }
}


// Container Type 을 λ”°λ₯΄λŠ”데, 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]
    }
}

// ν˜Ήμ€ μ •ν•΄μ Έμžˆμ§€ μ•Šμ•„λ„, 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]
    }
}

extension 으둜 associatedtype 지정

  • associatetype 을 μ •μ˜ν•  λ•Œ, νƒ€μž… μ œμ•½μ„ μΆ”κ°€ν•΄μ„œ
  • νŠΉμ • ꡬ쑰체, 클래슀, ν”„λ‘œν† μ½œμ„ μ€€μˆ˜ν•˜κ²Œ ν•  수 μžˆλ‹€.
protocol Container {
    associatedtype Item: Equatable
    mutating func append(_ item: Item)
    var count: Int { get }
    subscript(i: Int) -> Item { get }
}
  • associatedtype μ œμ•½μ‘°κ±΄ ν•˜μ—μ„œ ν”„λ‘œν† μ½œ μ‚¬μš©ν•˜κΈ°.
protocol SuffixableContainer: Container {
    associatedtype Suffix: SuffixableContainer where Suffix.Item == Item
    func suffix(_ size: Int) -> Suffix
}


extension Stack: SuffixableContainer {
    func suffix(_ size: Int) -> Stack {
        var result = Stack() // Stack 도 Generic Type μ΄λ‹ˆκΉŒ, Stack<Int>() 둜 μ œν•œν•  μˆ˜λ„ 있음.
        for index in (count-size)..<count {
            result.append(self[index])
        }
        return result
    }
    // Inferred that Suffix is Stack.
}
var stackOfInts = Stack<Int>()
stackOfInts.append(10)
stackOfInts.append(20)
stackOfInts.append(30)
let suffix = stackOfInts.suffix(2)
// suffix contains 20 and 30

8. Generic Where 절

  • νƒ€μž… μ œμ•½ <T: Equatable> 을 μ΄μš©ν•΄μ„œ Generic function, subscript, Type, parameter 의 νƒ€μž…μ— λŒ€ν•œ μš”κ΅¬μ‚¬ν•­μ„ μ •μ˜ν•  수 μžˆλ‹€.
  • associatetype 도 μ—­μ‹œ μš”κ΅¬μ‚¬ν•­ μ •μ˜κ°€ κ°€λŠ₯ν•˜λ‹€. where 절과 ν•¨κ»˜λΌλ©΄~
  • νŠΉμ • ν”„λ‘œν† μ½œμ„ μ€€μˆ˜ν•˜κ±°λ‚˜, νŠΉμ • νƒ€μž… νŒŒλΌλ―Έν„°μ™€ μ—°κ΄€λœ νƒ€μž…μ΄ 동일해야함을 λ‚˜νƒ€λ‚Ό 수 μžˆλ‹€.
// μ»¨ν…Œμ΄λ„ˆ 2κ°œκ°€ 같은 μˆœμ„œλ‘œ μ•„μ΄ν…œμ„ 가지고 μžˆλŠ”μ§€ ν™•μΈν•˜λŠ” ν•¨μˆ˜.
// C1, C2 κ°€ μ»¨ν…Œμ΄λ„ˆμ΄λ‚˜ 같은 νƒ€μž…μ€ μ•„λ‹μˆ˜λ„ μžˆλŠ” 상황.
func allItemsMatch<C1: Container, C2: Container>
    (_ someContainer: C1, _ anotherContainer: C2) -> Bool
    where C1.Item == C2.Item, C1.Item: Equatable {

        // Check that both containers contain the same number of items.
        if someContainer.count != anotherContainer.count {
            return false
        }

        // Check each pair of items to see if they're equivalent.
        for i in 0..<someContainer.count {
            if someContainer[i] != anotherContainer[i] {
                return false
            }
        }

        // All items match, so return true.
        return true
}

9. extension with Generic Where

  • ν™•μž₯μ—μ„œ Generic Where μ ˆμ„ μ‚¬μš©ν•  수 μžˆλ‹€.
// Stack 의 Element κ°€ Equatable ν•  λ•Œλ§Œ 이 λ©”μ„œλ“œ μΆ”κ°€.
extension Stack where Element: Equatable {
    func isTop(_ item: Element) -> Bool {
        guard let topItem = items.last else {
            return false
        }
        return topItem == item
    }
}

// Item 이 Double μΌλ•Œλ§Œ λ©”μ„œλ“œ μΆ”κ°€.
extension Container where Item == Double {
    func average() -> Double {
        var sum = 0.0
        for index in 0..<count {
            sum += self[index]
        }
        return sum / Double(count)
    }
}
print([1260.0, 1200.0, 98.6, 37.0].average()) // Prints "648.9"

10. 상황별 Where 절

  • 선언에 where μ ˆμ„ μ“Έ 수 μžˆλ‹€.
extension Container {
    // Int 일 λ•Œ μ‚¬μš© κ°€λŠ₯ν•œ λ©”μ„œλ“œ.
    func average() -> Double where Item == Int {
        var sum = 0.0
        for index in 0..<count {
            sum += Double(self[index])
        }
        return sum / Double(count)
    }
    // Equatable 일 λ•Œ μ‚¬μš© κ°€λŠ₯ν•œ λ©”μ„œλ“œ
    func endsWith(_ item: Item) -> Bool where Item: Equatable {
        return count >= 1 && self[count-1] == item
    }
}
let numbers = [1260, 1200, 98, 37]
print(numbers.average())  // Prints "648.75"
print(numbers.endsWith(37))  // Prints "true"
  • contextual Where λ₯Ό μ‚¬μš©ν•˜μ§€ μ•Šκ³  μ‹Άλ‹€λ©΄ μœ„μ—μ„œ μž‘μ„±ν•œ κ²ƒμ²˜λŸΌ 각각 extension 으둜 where 절 μΆ”κ°€.
  • κ²°κ΅­ ν•¨μˆ˜μ— 직접 where 절 μ“°λ˜μ§€..
  • extension 으둜 μ“°λ˜μ§€ λͺ¨λ‘ κ°€λŠ₯ν•˜λ‹€.

11. Associated Types with a Generic Where Clause

  • associatedtype 에 where μ ˆμ„ ν¬ν•¨μ‹œν‚¬ 수 μžˆλ‹€.
protocol Container {
    associatedtype Item
    mutating func append(_ item: Item)
    var count: Int { get }
    subscript(i: Int) -> Item { get }

    // Iterator.Element κ°€ Item 일 λ•Œ μ‚¬μš© κ°€λŠ₯ν•œ νƒ€μž… Iterator
    associatedtype Iterator: IteratorProtocol where Iterator.Element == Item
    func makeIterator() -> Iterator
}
  • λ‹€λ₯Έ ν”„λ‘œν† μ½œμ„ 상속할 λ•Œλ„ where 절둜 쑰건 μΆ”κ°€ κ°€λŠ₯.
protocol ComparableContainer: Container where Item: Comparable { }

12. Generic Subscripts

  • μ„œλΈŒμŠ€ν¬λ¦½νŠΈλ₯Ό Generic 으둜 μž‘μ„±ν•  수 μžˆλ‹€.
  • ν•¨μˆ˜μ²˜λŸΌ Subscript 문법 λ‹€μŒμ— where 절 μ‚¬μš©.
extension Container {
    subscript<Indices: Sequence>(indices: Indices) -> [Item]
        // λ°˜λ³΅ν•˜λŠ” 값이 Int μΌλ•Œλ§Œ κ°€λŠ₯ν•˜κ²Œ.
        where Indices.Iterator.Element == Int {
            var result: [Item] = []
            for index in indices {
                result.append(self[index])
            }
            return result
    }
}



질문

Generic에 λŒ€ν•΄ μ„€λͺ…ν•˜μ‹œμ˜€.

  • Swift 의 Type μ‹œμŠ€ν…œμ—μ„œ μ œκ³΅ν•˜λŠ” Type 을 μ’€ 더 μœ μ—°ν•˜κ²Œ μ‚¬μš©ν•  수 있게 ν•΄μ£ΌλŠ” 문법이닀.
  • Int, Double 같은 μ œκ³΅ν•˜λŠ” νƒ€μž…μ΄λ‚˜ 직접 μ„ μ–Έν•œ struct, class 같은 νƒ€μž…μ„ μΈμžλ‚˜ λ°˜ν™˜κ°’ ν‚€μ›Œλ“œμ— 직접 μ¨μ•Όν•˜λŠ”λ°,
  • 같은 역할을 ν•˜λŠ” ν•¨μˆ˜μΈλ° 인자의 νƒ€μž…λ§Œ λ‹¬λΌμ„œ 좔상화λ₯Ό ν•  수 μ—†λŠ” κ²½μš°μ—
  • κ·Έ λŒ€μ‹  μž„μ˜μ˜ νƒ€μž… 이름을 ν•˜λ‚˜ μ„ μ–Έν•΄μ„œ 두 νƒ€μž…μ΄κ°™κΈ°λ§Œ ν•˜λ©΄λœλ‹€λ˜μ§€, νƒ€μž…μ΄ νŠΉμ • ν”„λ‘œν† μ½œμ„ μ€€μˆ˜ν•˜κ±°λ‚˜ νŠΉμ • 클래슀라면 λ²”μš©μ μœΌλ‘œ ν•¨μˆ˜λ₯Ό μ“Έ 수 있게 ν•  수 μžˆλ‹€.<T>
  • 클래슀 ꡬ쑰체 μ—΄κ±°ν˜•μ„ μ„ μ–Έν•  λ•Œλ„ μ‚¬μš©ν•  수 μžˆλ‹€.
  • where μ ˆμ„ μ΄μš©ν•΄μ„œ ν•΄λ‹Ή Generic function, Generic Type 에 λŒ€ν•œ 쑰건을 쀄 μˆ˜λ„ μžˆλ‹€.
profile
0λ…„μ°¨ iOS κ°œλ°œμžμž…λ‹ˆλ‹€.

0개의 λŒ“κΈ€