为 Collection 一致性提供默认实现可防止额外的下标要求
Providing a default implementation for Collection conformance prevents additional subscript requirements
我有一个协议,它本身符合 Swift 的 Collection
协议,并且需要一个额外的下标 (Key) -> Value?
return 与给定的值关联键,仅当它存在时(很像 Swift 的 Dictionary
)。
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()
的 return 类型应该强制带有签名 (Int) -> (Key, String)
的下标无论如何满足 Collection
的要求。
有人知道我在这里错过了什么吗?
两个问题:
您在 SearchTree
协议中的下标声明需要在其后加上 { get }
。
Collection
需要 returns 其 Element
的下标。你有两个下标,其中一个是returns一个String?
,一个是returns一个(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?
编辑:
以上为Swift4;但是,对于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 }
}
我有一个协议,它本身符合 Swift 的 Collection
协议,并且需要一个额外的下标 (Key) -> Value?
return 与给定的值关联键,仅当它存在时(很像 Swift 的 Dictionary
)。
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()
的 return 类型应该强制带有签名 (Int) -> (Key, String)
的下标无论如何满足 Collection
的要求。
有人知道我在这里错过了什么吗?
两个问题:
您在
SearchTree
协议中的下标声明需要在其后加上{ get }
。Collection
需要 returns 其Element
的下标。你有两个下标,其中一个是returns一个String?
,一个是returns一个(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?
编辑:
以上为Swift4;但是,对于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 }
}