问题描述
查看,我正在尝试为 CollectionType
实现一个名为 CollectionOf
的等价物,但是我遇到了其中一个约束:
Looking at this question, I'm trying to implement an equivalent for CollectionType
called CollectionOf
, but I'm having trouble with one of the constraints:
struct CollectionOf<T, Index: ForwardIndexType>: CollectionType {
init<C: CollectionType where C.Generator.Element == T, C.Index == Index>(_ collection: C) {
// etc.
}
// etc.
}
这不能编译。让我们忽略一个事实,即我还没有实现 CollectionType
的成员。我会做到这一点。我面临的问题是编译器不喜欢我的 init
。它抱怨说:同类型约束索引不符合所需的协议ForwardIndexType。显然它确实如此。
This does not compile. Let's ignore the fact that I haven't implemented the members of CollectionType
yet. I'll get to that. The problem I face is that the compiler doesn't like my init
. It complains, "Same-type constraint Index does not conform to required protocol ForwardIndexType." Clearly it does.
也许我们有一个编译器错误。也许我的语法错了。无论如何,我如何实现 CollectionOf
?
Perhaps we have a compiler bug. Perhaps my syntax is wrong. Whatever the case, how can I implement CollectionOf
?
这是一个工作实现。由于上面提到的问题,它有一个严重的缺陷,即 CollectionType
的 Index typealias
不受约束与包装的 CollectionType
相同。这意味着我被强制转换,这在理论上会在运行时造成问题,而不是在编译时,这会破坏静态类型的目的。
Here is a working implementation. Due to the problem noted above, it suffers from the serious flaw that the Index typealias
of CollectionType
is not constrained to be same as that of the wrapped CollectionType
. This means I am forced to cast, which could in theory cause a problem at runtime rather than at compilation time, which defeats the purpose of static typing.
struct CollectionOf<T, I: ForwardIndexType>: CollectionType {
private let _generate: () -> GeneratorOf<T>
private let _startIndex: () -> I
private let _endIndex: () -> I
private let _subscript: (I) -> T
init<C: CollectionType where C.Generator.Element == T>(_ collection: C) {
_generate = { GeneratorOf(collection.generate()) }
_startIndex = { collection.startIndex as I }
_endIndex = { collection.endIndex as I }
_subscript = { i in collection[i as C.Index] }
}
var startIndex: I {
return _startIndex()
}
var endIndex: I {
return _endIndex()
}
func generate() -> GeneratorOf<T> {
return _generate()
}
subscript (i: I) -> T {
return _subscript(i)
}
}
推荐答案
无论出于何种原因,它看起来像编译器不在内部查看 CollectionType
来发现其索引已经是 ForwardIndex
。如果您将 C.Index:ForwardIndexType
添加到通用约束的where子句中,编译器就会停止对您进行操作。
For whatever reason, it looks like the compiler isn't looking inside CollectionType
to find that its index is already a ForwardIndex
. If you add C.Index: ForwardIndexType
to the where clause of your generic constraint, the compiler stops bugging you.
以下是一个实现 CollectionOf< T>
的方法,其索引始终为 Int
。这里的一个缺点是,一些操作,即找到
endIndex
和下标,可能是 O ( N ),而不是 0 (1)。如果传入的集合具有类型 Int
的索引,则所有操作都将是 O (1)。
Here's a way to implement
CollectionOf<T>
with an index that is always an Int
. The one downside here is that some operations, namely finding endIndex
and subscripting, may be O(N) instead of O(1). If the collection passed in has an index of type Int
, all operations will be 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)
}
}
这篇关于如何在Swift中实现CollectionOf的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!