协议可以使用关键字定义关联的类型需求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
// 这些是允许的:
func displayValues<T: Container>(container: T) { ... }
class MyClass<T: Container> { let container: T }associatedtype通过在协议期望associatedtype出现的地方提供给定类型,符合协议的类型可以隐式满足要求:
struct ContainerOfOne<T>: Container {
let count = 1 // 满足计数要求
var value: T
// 隐式满足下标关联类型要求,
// 通过将下标分配/返回类型定义为T
// 因此Swift会推断出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要求。)
一个associatedtype也可以通过使用一个明确的满足typealias:
struct ContainerOfOne<T>: Container { typealias Element = T
subscript(index: Int) -> Element { ... }
// ...
}扩展也是如此:
// 公开一个8位整数作为布尔值的集合(每一位一个)。
extension UInt8: Container {
// 如上所述,可以推断出这种类型别名
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 {} // 数组满足所有要求,包括元素