查看this question,我试图为名为CollectionType
的{{1}}实施等效内容,但我遇到了其中一个限制问题:
CollectionOf
这不编译。让我们忽略这样一个事实:我还没有实现struct CollectionOf<T, Index: ForwardIndexType>: CollectionType {
init<C: CollectionType where C.Generator.Element == T, C.Index == Index>(_ collection: C) {
// etc.
}
// etc.
}
的成员。我会接受这个。我面临的问题是编译器不喜欢我的CollectionType
。它抱怨,&#34;相同类型约束索引不符合所需协议ForwardIndexType。&#34;显然它确实如此。
也许我们有编译错误。也许我的语法错了。无论如何,我如何实施init
?
这是一个有效的实施方案。由于上面提到的问题,它存在严重的缺陷,CollectionOf
Index typealias
不限于与包裹的CollectionType
相同。这意味着我被迫进行强制转换,这在理论上可能会在运行时而不是在编译时引起问题,这会破坏静态类型的目的。
CollectionType
答案 0 :(得分:3)
无论出于何种原因,看起来编译器没有在CollectionType
内查找其索引已经是ForwardIndex
。如果将C.Index: ForwardIndexType
添加到泛型约束的where子句中,编译器就会停止窃听你。
这是一种实现CollectionOf<T>
的方法,其索引始终为Int
。这里的一个缺点是,一些操作,即查找endIndex
和下标,可能是 O ( N )而不是 O ( 1)。如果传入的集合具有类型Int
的索引,则所有操作都将是 O (1)。
struct CollectionOf<T>: CollectionType {
typealias Index = Int
private let _generate: () -> GeneratorOf<T>
private let _subscript: (Int) -> T
private let _endIndex: () -> Int
init<C: CollectionType where C.Generator.Element == T>(_ collection: C) {
_generate = { GeneratorOf(collection.generate()) }
_subscript = {
(i: Int) in
if C.Index.self is Int.Type {
return collection[((collection.startIndex as Int) + i) as C.Index]
} else {
let index = reduce(0..<i, collection.startIndex) { $0.0.successor() }
return collection[index]
}
}
_endIndex = {
if C.Index.Distance.self is Int.Type {
return distance(collection.startIndex, collection.endIndex) as Int
} else {
return reduce(collection.startIndex..<collection.endIndex, 0) { $0.0 + 1 }
}
}
}
var startIndex: Int {
return 0
}
var endIndex: Int {
return _endIndex()
}
func generate() -> GeneratorOf<T> {
return _generate()
}
subscript (i: Int) -> T {
return _subscript(i)
}
}
答案 1 :(得分:2)
将CollectionType.Index.Distance
用作CollectionOf<T>.Index
可以简化事情:
struct CollectionOf<T>:CollectionType {
private let _generate: () -> GeneratorOf<T>
private let _endIndex: () -> Int
private let _subscript: (Int) -> T
init<C: CollectionType where C.Generator.Element == T, C.Index.Distance == Int>(_ base: C) {
_generate = { GeneratorOf(base.generate()) }
_endIndex = { distance(base.startIndex, base.endIndex) }
_subscript = { base[advance(base.startIndex, $0)] }
}
var startIndex: Int { return 0 }
var endIndex: Int { return _endIndex() }
subscript (i: Int) -> T { return _subscript(i) }
func generate() -> GeneratorOf<T> { return _generate() }
}
此约束C.Index.Distance == Int
,但据我所知,内置Index.Distance
的所有CollectionType
均为Int
。所以这里没有实际缺陷。
如果您确实要接受所有CollectionType
,请使用IntMax
:
struct CollectionOf<T>:CollectionType {
private let _generate: () -> GeneratorOf<T>
private let _endIndex: () -> IntMax
private let _subscript: (IntMax) -> T
init<C: CollectionType where C.Generator.Element == T>(_ base: C) {
_generate = { GeneratorOf(base.generate()) }
_endIndex = { distance(base.startIndex, base.endIndex).toIntMax() }
_subscript = { base[advance(base.startIndex, C.Index.Distance($0))] }
}
var startIndex: IntMax { return 0 }
var endIndex: IntMax { return _endIndex() }
subscript (i: IntMax) -> T { return _subscript(i) }
func generate() -> GeneratorOf<T> { return _generate() }
}
这是有效的,因为CollectionType.Index.Distance
是_SignedIntegerType
而_SignedIntegerType
有toIntMax()
和init(_: IntMax)
答案 2 :(得分:1)
这个答案在技术上仍然是正确的。 Nate Cook有一个聪明的解决方法,我决定将其标记为正确。
经过大量搜索后发现,截至本文撰写时,我认为无法创建通用类型安全CollectionOf
。问题可以归结为:
protocol AwesomeType {
typealias Crazy: ForwardIndexType
}
struct AwesomeOf<C: ForwardIndexType> {
init<A: AwesomeType where A.Crazy == C>(_ awesome: A) {
}
}
我们试图在初始化程序中告诉编译器,关联类型Crazy
(必须符合ForwardIndexType
协议)与我们的类级泛型类型参数{{ 1}},已根据需要声明符合C
。
不幸的是,这不起作用。在方法级泛型约束中,编译器将类级泛型参数视为不受约束,从而产生错误。
我做了很多测试,发现没有什么能与这个假设相矛盾。如果有人知道如何解决这个问题,我很想知道。
这意味着不幸的是,传递类型安全(但不是通用的)ForwardIndexType
的唯一方法是泄漏类型信息,如下所示:
CollectionOf
问题在于它不够通用。它泄漏了底层集合的类型,例如,我们必须说class CollectionOf<C: CollectionType>: CollectionType {
init(_ collection: C) {
}
}
而不是CollectionOf<Int, Int>
。这是一个真正的耻辱,我希望它在未来的Swift版本中得到修复。