相关类型要求
协议可以使用 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