相關型別要求
協議可以使用 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