使用扩展允许您保持协议一致性的声明在实现该协议的方法旁边。
如果没有扩展,想象声明你的类型为:使用扩展,在那里你捆绑在一起的协议的执行情况,实现它的这些具体方法
struct Queue<T>: SequenceType, ArrayLiteralConvertible, Equatable, Printable, Deflectable, VariousOtherables {
// lotsa code...
// and here we find the implementation of ArrayLiteralConvertible
/// Create an instance containing `elements`.
init(arrayLiteral elements: T…) {
etc
}
}
进行对比:
struct Queue<T> {
// here go the basics of queue - the essential member variables,
// maybe the enqueue and dequeue methods
}
extension SequenceType {
// here go just the specifics of what you need for a sequence type
typealias Generator = GeneratorOf<T>
func generate() -> Generator {
return GeneratorOf {
// etc.
}
}
}
extension Queue: ArrayLiteralConvertible {
init(arrayLiteral elements: T...) {
// etc.
}
}
是的,你可以用// MARK
来标记你的协议实现(并且记住,你可以结合使用这两种技术),但是你仍然会被分割到文件的顶部,在那里协议支持的声明将会是b e,以及文件的主体,你的实现在哪里。另外,请记住,如果您正在实施一个协议,您将随时获得来自IDE的有用(如果稍为冗长)反馈,告诉您您还需要执行哪些操作。使用扩展来逐个执行每个协议使它(对我而言)比一次完成所有操作(或者在添加它们时从上到下跳来跳去)要容易得多。
鉴于此,将其他非协议但相关的方法分组为扩展也很自然。
我实际上偶尔发现它令人沮丧,当你不能做到这一点。例如,
extension Queue: CollectionType {
// amongst other things, subscript get:
subscript(idx: Index) -> T {
// etc
}
}
// all MutableCollectionType adds is a subscript setter
extension Queue: MutableCollectionType {
// this is not valid - you’re redeclaring subscript(Index)
subscript(idx: Int) -> T {
// and this is not valid - you must declare
// a get when you declare a set
set(val) {
// etc
}
}
}
因此,您必须在同一个扩展中实现两者。
使用你喜欢的任何一个,但扩展使它比单纯的'MARK:'更明确,明确指出它开始的位置和结束位置。坦率地说,这不是一个问题,因为我会同时使用'MARK:'和'extension'。 'extension'的另一个优点是您可以轻松地折叠该代码(例如“编辑器” - “代码折叠...” - “折叠”或单击带阴影的左边距)。 – Rob 2015-11-19 22:03:55