Swift 2.0 协议扩展和 Java/C# 抽象 类 之间有区别吗?

Is there a difference between Swift 2.0 protocol extensions and Java/C# abstract classes?

随着Swift2.0中协议扩展的加入,协议似乎基本变成了Java/C#抽象类。我能看到的唯一区别是抽象 类 限制为单一继承,而 Swift 类型可以符合任意数量的协议。

这是对Swift 2.0协议的正确理解,还是有其他差异?

有几个重要的区别...

协议扩展可以与 value types 以及 classes 一起使用。

值类型是结构和枚举。例如,您可以扩展 IntegerArithmeticType 以将 isPrime 属性 添加到所有整数类型(UInt8Int32 等)。或者,您可以将协议扩展与结构扩展结合起来,为多个现有类型添加相同的功能——比如,为 CGPointCGVector 添加向量算术支持。

Java 和 C# 在语言级别上实际上没有 user-creatable/extensible "plain old data" 类型,因此这里没有真正的类似物。 Swift 大量使用值类型 — 与 ObjC、C# 和 Java 不同,在 Swift 中甚至集合都是写时复制值类型。这有助于解决很多关于可变性和线程安全的问题,因此创建自己的值类型而不是总是使用 classes 可以帮助您编写更好的代码。 (请参阅 WWDC15 中的 Building Better Apps with Value Types in Swift。)

可以限制协议扩展。

例如,您可以有一个向 CollectionType only when the collection's underlying element type meets some criteria. Here's one that finds the maximum element of a collection — on a collection of numbers or strings, this property shows up, but on a collection of, say, UIViews (which aren't Comparable) 添加方法的扩展,这个 属性 不存在。

extension CollectionType where Self.Generator.Element: Comparable {
    var max: Self.Generator.Element {
        var best = self[self.startIndex]
        for elt in self {
            if elt > best {
                best = elt
            }
        }
        return best
    }
}

(小贴士:这个例子今天出现在优秀的 NSBlog 上。)

在这些 WWDC15 演讲中有一些更好的受限协议扩展示例(可能还有更多,但我还没有赶上视频):

抽象 classes——在任何语言中,包括 ObjC 或 Swift,它们是编码约定而不是语言特性——沿着 class 继承线工作,所以所有subclasses 继承了抽象的 class 功能,不管它是否有意义。

协议可以选择静态或动态调度。

这个更让人头疼,但如果使用得当,它会非常强大。这是一个基本示例(同样来自 NSBlog):

protocol P {
    func a()
}
extension P {
    func a() { print("default implementation of A") }
    func b() { print("default implementation of B") }
}
struct S: P {
    func a() { print("specialized implementation of A") }
    func b() { print("specialized implementation of B") }
}

let p: P = S()
p.a() // -> "specialized implementation of A"
p.b() // -> "default implementation of B"

正如 Apple 在 Protocol-Oriented Programming in Swift 中指出的那样,您可以使用它来选择哪些功能应该是可以由采用协议的客户端自定义的覆盖点,以及哪些功能应该始终是协议提供的标准功能.

一个类型可以从多个协议中获得扩展功能。

正如您已经注意到的,协议一致性是多重继承的一种形式。如果您的类型符合多个协议,并且这些协议具有扩展,则您的类型将获得满足其约束的所有扩展的功能。

您可能知道为 classes 提供多重继承的其他语言,这会打开一个丑陋的蠕虫罐头,因为您不知道如果从多个 classes 具有相同的成员或功能。 Swift 2在这方面好一点:

  • 协议扩展之间的冲突是 always resolved in favor of the most constrained extension。因此,例如,视图集合上的方法总是胜过任意集合上的同名方法(这反过来又胜过任意序列上的同名方法,因为 CollectionType 是 [=23 的子类型=]).

  • 调用存在冲突的 API 是编译错误,而不是运行时歧义。

协议(和扩展)无法创建存储。

协议定义可以要求采用该协议的类型必须实现 属性:

protocol Named {
    var name: String { get } // or { get set } for readwrite 
}

采用该协议的类型可以选择是将其实现为存储 属性 还是计算 属性,但无论哪种方式,采用的类型都必须声明其实现 属性 .

扩展可以实现计算属性,但扩展不能 添加一个stored属性。无论是协议扩展还是特定类型(class、结构或枚举)的扩展都是如此。

相比之下,class 可以添加存储属性以供子class 使用。虽然 Swift 中没有语言特性,但 强制 超级 class 是抽象的(也就是说,你不能让编译器禁止创建实例) ,如果你想使用这个能力,你总是可以非正式地创建 "abstract" superclasses。