Swift协议不能是通用的,所以不幸的是我不能简单地定义一个getter来返回CollectionOf< Type>.我已经使用以下抽象基类实现了这种行为,并从中继承了我的集合,但我希望可能有更多的Swift-y和内置方法来实现这一点,希望也不需要子类化:
class AnyCollectionOf<MemberT,IndexT: ForwardindexType>: CollectionType { // Sequence Type func generate() -> GeneratorOf<MemberT> { fatalError("must override") } // Collection Type typealias Index = IndexT typealias Element = MemberT subscript (index: Index) -> Element { get { fatalError("must override") } } var startIndex: Index { get { fatalError("must override") } } var endindex: Index { get { fatalError("must override") } } }
解决方法
SequenceType和CollectionType等协议要求实现它们的类提供类型化,以填充实现细节,例如元素类型,如上所述.一旦协议添加了这些要求,它就再也不能用作独立类型.您只能根据符合它的特定类声明接口. (如果你试图解决这个问题,你可能还记得看到关于“关联类型要求”的编译器错误不是很有帮助.)
这是你不能写的基本原因
func countItems(collection: CollectionType) -> Int { ... }
但必须改为写
func countItems<T: CollectionType>(collection: T) -> Int { ... }
后一种形式确保编译器可以访问实现CollectionType协议的实际类型的对象(T).
但是,如果您考虑封装而不是继承,那么您可能仍然可以更清晰地实现您要执行的操作.除了核心的CollectionType方法之外,您可以使用一个简单的包装器来阻止访问所有内容:
struct ShieldedCollection<UCT: CollectionType> : CollectionType { private var underlying: UCT func generate() -> UCT.Generator { return underlying.generate() } subscript(index: UCT.Index) -> UCT.Generator.Element { return underlying[index] } var startIndex: UCT.Index { return underlying.startIndex } var endindex: UCT.Index { return underlying.endindex } } var foo = [1,2,3] var shieldedFoo = ShieldedCollection(underlying: foo)
(这里,UCT =“底层集合类型”.)
ShieldedCollection仍然具有CollectionType的所有常见类型,但由于这些可以从上下文推断出来,因此您不必明确指定它们.
这种通用方法的缺陷,不幸的是它是一个相当重要的方法,是底层类型仍然泄漏到API中.上例中的shieldedFoo类型是
ShieldedCollection<Array<Int>>
由于您的基础集合是自定义对象,因此其名称仍可能在API中泄漏,即使客户端无法直接访问该类本身.请注意,这不是一个功能问题,因为不应该通过ShieldedCollection包装器访问底层对象.此外,消费者永远不必自己编写类型 – 他们可以只使用prevIoUsItems()的结果作为CollectionType,编译器将解开所有内容.
如果您真的想要隐藏所有提及的底层集合类型,您可以通过在ShieldedCollection中移动UCT定义来编写上面包装器的特定于任务的模拟:
struct ShieldedCollection<T> : CollectionType // Changed! { typealias UCT = [T] // Added! private var underlying: UCT // Everything else identical func generate() -> UCT.Generator { return underlying.generate() } subscript(index: UCT.Index) -> UCT.Generator.Element { return underlying[index] } var startIndex: UCT.Index { return underlying.startIndex } var endindex: UCT.Index { return underlying.endindex } } var foo = [1,3] var shieldedFoo = ShieldedCollection(underlying: foo)
在这里,您通过放弃完全的通用性来使返回类型整洁 – 此版本的ShieldedCollection仅适用于作为数组的基础CollectionTypes. (当然,您只需在UCT的类型中替换您自己的自定义集合类型.)
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。