type alias๋ฅผ ๊ณต๋ถ€ํ•˜๋ฉด์„œ ๋งˆ์ฃผ์ณค๋˜ associated type์— ๋Œ€ํ•ด ์•Œ์•„๋ณธ๋‹ค.

Type Constraints

func someFunction<T: SomeClass, U: SomeProtocol>(someT: T, someU: U) {
    // function body goes here
}
 
func findIndex<T: Equatable>(of valueToFind: T, in array:[T]) -> Int? {
    for (index, value) in array.enumerated() {
        if value == valueToFind {
            return index
        }
    }
    return nil
}

generic์„ ์‚ฌ์šฉํ•˜๋Š”๋ฐ ์žˆ์–ด, ๋‚ด๋ถ€์—์„œ ์‚ฌ์šฉํ•˜๋Š” ํƒ€์ž…์— ์ œ์•ฝ์‚ฌํ•ญ์„ ๊ฑธ ์ˆ˜ ์žˆ๋‹ค. findIndex์˜ ๊ฒฝ์šฐ T Type์ด Equatable์ด์–ด์•ผ๋งŒ ์‚ฌ์šฉ๊ฐ€๋Šฅํ•˜๋‹ค.

Associated Types

ํ”„๋กœํ† ์ฝœ์„ ์ •์˜ํ•  ๋•Œ, ํ•˜๋‚˜ ์ด์ƒ์˜ ๊ด€๋ จ ์œ ํ˜•์„ ํ”„๋กœํ† ์ฝœ ์ •์˜์˜ ์ผ๋ถ€๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. Type Alias์—์„œ๋„ ์‚ฌ์šฉํ–ˆ๋Š”๋ฐ, ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

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

Container ํ”„๋กœํ† ์ฝœ์„ ์ค€์ˆ˜ํ•˜๋Š” ๋ชจ๋“  ํƒ€์ž…์€, ์ €์žฅํ•˜๋Š” ๊ฐ’์˜ ํƒ€์ž…์„ ๋ช…์‹œํ•ด์•ผ ํ•˜๊ณ , ์ด ๊ฐ’์€ ์ปจํ…Œ์ด๋„ˆ์— ์ถ”๊ฐ€๋  ์ˆ˜ ์žˆ๋Š” ํƒ€์ž…์ž„์„ ๋ณด์žฅํ•ด์•ผํ•œ๋‹ค. ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ subscript๋ฅผ ํ†ตํ•ด ๋ฐ˜ํ™˜๋  ์ˆ˜ ์žˆ๋Š” ํƒ€์ž…์ด์–ด์•ผ ํ•จ๋„ ๋ณด์žฅํ•ด์•ผํ•œ๋‹ค. ์ด๋ฅผ ์œ„ํ•ด์„œ, Container ํ”„๋กœํ† ์ฝœ์€ ๊ตฌ์ฒด์ ์ธ ์ปจํ…Œ์ด๋„ˆ์˜ ํƒ€์ž…์„ ์•Œ์ง€ ๋ชปํ•˜๋”๋ผ๋„, ์ปจํ…Œ์ด๋„ˆ๊ฐ€ ๊ฐ€์งˆ ์š”์†Œ๋“ค์˜ ํƒ€์ž…์„ ์–ธ๊ธ‰ํ•  ํ•„์š”๊ฐ€ ์žˆ๋‹ค. ๋‹ค์‹œ ๋งํ•ด, Container ํ”„๋กœํ† ์ฝœ์€ append(_:) ๋ฉ”์†Œ๋“œ๋ฅผ ํ†ตํ•ด ์ „๋‹ฌ๋˜๋Š” ๊ฐ’์ด ์ปจํ…Œ์ด๋„ˆ์˜ ์š”์†Œ์™€ ๊ฐ™์€ ํƒ€์ž…์ด์–ด์•ผ ํ•œ๋‹ค๋Š” ๊ฒƒ๊ณผ ์ปจํ…Œ์ด๋„ˆ์˜ subscript ์—ญ์‹œ ์ปจํ…Œ์ด๋„ˆ์˜ ์š”์†Œ์™€ ๊ฐ™์€ ํƒ€์ž…์ด์–ด์•ผ ํ•œ๋‹ค๋Š” ๊ฒƒ์„ ๋ช…์‹œํ•ด์•ผํ•œ๋‹ค. ์ด๋ฅผ ์œ„ํ•ด์„œ Container ํ”„๋กœํ† ์ฝœ์€ associated type์ธ Item์„ ํ™œ์šฉํ•˜๋Š” ๊ฒƒ์ด๋‹ค.

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 // ์ถ”์ƒ ํƒ€์ž… Item์„ Int๋กœ ๋ฐ”๊ฟ” ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•œ ๊ตฌ๋ฌธ
    mutating func append(_ item: Int) {
        self.push(item)
    }
    var count: Int {
        return items.count
    }
    subscript(i: Int) -> Int {
        return items[i]
    }
}

IntStack ํƒ€์ž…์€ Container ํ”„๋กœํ† ์ฝœ์„ ์ฒดํƒํ•˜๊ณ  ์„ธ ๊ฐ€์ง€ ํ•„์ˆ˜ ์š”๊ตฌ์‚ฌํ•ญ์„ ์ค€์ˆ˜ํ•˜๊ณ  ์žˆ๊ณ , associatedtype์ธ Item ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด Int ํƒ€์ž…์„ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๋‹ค. typealias Item = Int ๋Š” ํ”„๋กœํ† ์ฝœ์„ ์ค€์ˆ˜ํ•˜๊ธฐ ์œ„ํ•ด์„œ ์ถ”์ƒ ํƒ€์ž…์ธ Item์„ Int ๋กœ ๋ฐ”๊ฟ” ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•œ ๊ตฌ๋ฌธ์ด๋‹ค. Swift์˜ ํƒ€์ž… ์ถ”๋ก  ๋•๋ถ„์— ์ด ๊ตฌ๋ฌธ์€ ์ƒ๋žต ๊ฐ€๋Šฅํ•˜๋‹ค.

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]
    }
}

์œ„์™€ ๊ฐ™์ด generic stack ํƒ€์ž…์„ ํ†ตํ•ด์„œ๋„ Container ํ”„๋กœํ† ์ฝœ์„ ์ค€์ˆ˜ํ•  ์ˆ˜ ์žˆ๋‹ค.

Adding Constraints to an Associated Type

Associated Type์—๋„ Type Constraint๋ฅผ ๊ฑธ ์ˆ˜ ์žˆ๋‹ค.

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

Using a Protocol in Its Associated Typeโ€™s Constraints

ํ”„๋กœํ† ์ฝœ์€ ์ž๊ธฐ ์ž์‹ ์˜ ์š”๊ตฌ์‚ฌํ•ญ์˜ ์ผ๋ถ€๋กœ ํ‘œํ˜„๋  ์ˆ˜ ์žˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ๋‹ค์Œ์€ Container ํ”„๋กœํ† ์ฝœ์— suffix(_:) ๋ฉ”์†Œ๋“œ๋ฅผ ์ถ”๊ฐ€ํ•˜์—ฌ ๊ธฐ์กด์˜ ํ”„๋กœํ† ์ฝœ์„ ๊ฐœ์„ ํ•œ ์ฝ”๋“œ์ด๋‹ค. suffix(_:)๋Š” ์ปจํ…Œ์ด๋„ˆ์˜ ๋์—์„œ๋ถ€ํ„ฐ ์ฃผ์–ด์ง„ ๊ฐœ์ˆ˜์˜ ์š”์†Œ๋ฅผ ๋ฐ˜ํ™˜ํ•˜์—ฌ, Suffix ํƒ€์ž…์˜ ์ธ์Šคํ„ด์Šค์— ์ €์žฅํ•˜๋Š” ๋ฉ”์†Œ๋“œ์ด๋‹ค.

protocol SuffixableContainer: Container {
    associatedtype Suffix: SuffixableContainer where Suffix.Item == Item
    func suffix(_ size: Int) -> Suffix
}

์—ฌ๊ธฐ์„œ Suffix๋Š” associated type์ด๋ฉฐ, ๋‘๊ฐ€์ง€ ์ œ์•ฝ ์กฐ๊ฑด์„ ๊ฐ€์ง„๋‹ค.

  1. SuffixableContainer๋ฅผ ์ค€์ˆ˜ํ•ด์•ผ ํ•œ๋‹ค.
  2. ๊ทธ๋ฆฌ๊ณ  ํ•ด๋‹น type์˜ Item์€ Container์˜ Item ํƒ€์ž…๊ณผ ๊ฐ™์•„์•ผ ํ•œ๋‹ค.
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 Stack: SuffixableContainer {
    func suffix(_ size: Int) -> Stack {
        var result = Stack()
        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

์ด ์ฝ”๋“œ์—์„œ Stack์˜ Suffix associated type์€ ๋˜ํ•œ Stack ์ด๊ณ , ๋”ฐ๋ผ์„œ Stack์˜ suffix ์ž‘์—…์€ ๋˜ ๋‹ค๋ฅธ Stack ์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

Reference