泛型 – 你可以在Swift中指定一个返回类型作为特定类型的任何集
我已经实现了一个自定义队列对象,我想用它来存储控制器中的先前项目.我想在我的控制器中将此类型用作私有变量,并且仅将其作为简单的CollectionType兼容对象公开给外部,以便客户端可以迭代或索引对象,而无需了解任何特定于类的详细信息,例如clear()函数.
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") } } } 解决方法
不幸的是,你的标题问题的答案是否定的:没有办法将CollectionType作为可以用作变量或返回类型的独立类型进行陪审.
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的类型中替换您自己的自定义集合类型.) (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |