我有一个协议,它本身符合Swift的Collection
协议,并且需要额外的下标(Key) -> Value?
返回与给定键相关联的值,只要它存在(非常类似于Swift的Dictionary
1}}确实)。
protocol SearchTree: Collection {
subscript(key: Int) -> String? { get }
}
struct ConformingTree: SearchTree {
// Implementation ...
}
现在,我想用所有Collection
要求的默认实现扩展它,加上我的附加下标(我想实现细节是无关紧要的,这就是我删除它们的原因)。
protocol SearchTree: Collection {
subscript(key: Int) -> String? { get }
}
extension SearchTree {
// MARK: Conformance to Sequence
func makeIterator() -> AnyIterator<(key: Int, value: String)> { /* ... */ }
// MARK: Conformance to Collection
var startIndex: Int { /* ... */ }
var endIndex: Int { /* ... */ }
func index(after i: Int) -> Int { /* ... */ }
subscript(key: Int) -> (key: Int, value: String) { /* ... */ }
// MARK: Conformance to SearchTree
subscript(key: Int) -> String? { /* ... */ }
}
struct ConformingTree: SearchTree {
// Removing previous implementations ...
}
不幸的是,此代码将失败,Swift抱怨ConformingTree
不符合Collection
,除非我保留了符合类型中至少一个下标的实现。
struct ConformingTree: SearchTree {
subscript(key: Int) -> String? { /* ... */ }
}
我原本以为Swift无法推断扩展中正确下标的类型。但这似乎不太可能,因为它最终可以确定哪个实现对应于哪个协议要求,如果我将它们推入符合类型。据我了解,makeIterator()
的返回类型应强制带有签名(Int) -> (Key, String)
的下标,以满足Collection
的要求。
有谁知道我在这里缺少什么?
答案 0 :(得分:1)
两个问题:
您在SearchTree
协议中声明的下标需要{ get }
之后。
Collection
需要一个返回其Element
的下标。你有两个下标,其中一个返回String?
,其中一个返回(key: Int, value: String)
,但这些都不是编译器需要的Element
;因此类型不符合Collection
。如果您在协议或扩展中定义Element
,则应编译。
在协议中:
associatedtype Element = (key: Int, value: String)
或:
associatedtype Element = String?
或者在扩展程序中:
typealias Element = (key: Int, value: String)
或:
typealias Element = String?
编辑:
以上适用于Swift 4;但是,对于Swift 3,除了_Element
之外,还需要定义Element
。将代码复制并粘贴到项目中,以下协议声明会导致在Swift 3中编译所有内容:
protocol SearchTree: Collection {
associatedtype Element = (key: Int, value: String)
associatedtype _Element = (key: Int, value: String)
subscript(key: Int) -> String? { get }
}