相關型別要求

協議可以使用 associatedtype 關鍵字定義關聯的型別要求

protocol Container {
    associatedtype Element
    var count: Int { get }
    subscript(index: Int) -> Element { get set }
}

具有關聯型別要求的協議只能用作通用約束

// These are NOT allowed, because Container has associated type requirements:
func displayValues(container: Container) { ... }
class MyClass { let container: Container }
// > error: protocol 'Container' can only be used as a generic constraint
// > because it has Self or associated type requirements

// These are allowed:
func displayValues<T: Container>(container: T) { ... }
class MyClass<T: Container> { let container: T }

符合協議的型別可以通過提供協議期望 associatedtype 出現的給定型別來隱式地滿足 associatedtype 要求:

struct ContainerOfOne<T>: Container {
    let count = 1          // satisfy the count requirement
    var value: T
    
    // satisfy the subscript associatedtype requirement implicitly,
    // by defining the subscript assignment/return type as T
    // therefore Swift will infer that T == Element
    subscript(index: Int) -> T {
        get {
            precondition(index == 0)
            return value
        }
        set {
            precondition(index == 0)
            value = newValue
        }
    }
}

let container = ContainerOfOne(value: "Hello")

(請注意,為了增加此示例的清晰度,通用佔位符型別名為 T - 更合適的名稱將是 Element,這將影響協議的 associatedtype Element。編譯器仍將推斷通用佔位符 Element 用於滿足 associatedtype Element 要求。)

通過使用 typealias 也可以明確地滿足 associatedtype

struct ContainerOfOne<T>: Container {

    typealias Element = T
    subscript(index: Int) -> Element { ... }

    // ...
}

擴充套件也是如此:

// Expose an 8-bit integer as a collection of boolean values (one for each bit).
extension UInt8: Container {

    // as noted above, this typealias can be inferred
    typealias Element = Bool

    var count: Int { return 8 }
    subscript(index: Int) -> Bool {
        get {
            precondition(0 <= index && index < 8)
            return self & 1 << UInt8(index) != 0
        }
        set {
            precondition(0 <= index && index < 8)
            if newValue {
                self |= 1 << UInt8(index)
            } else {
                self &= ~(1 << UInt8(index))
            }
        }
    }
}

如果符合要求的型別已滿足要求,則無需實施:

extension Array: Container {}  // Array satisfies all requirements, including Element