小编典典

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

swift

通过在Swift 2.0中添加协议扩展,似乎协议基本上已经成为Java /
C#抽象类。我可以看到的唯一区别是抽象类仅限于单个继承,而Swift类型可以符合任何数量的协议。

这是对Swift 2.0中协议的正确理解,还是有其他区别?


阅读 293

收藏
2020-07-07

共1个答案

小编典典

有几个重要的区别…

协议扩展可以与值类型以及类一起使用。

值类型是结构和枚举。例如,你可以扩展IntegerArithmeticType到增加isPrime财产所有整数类型(UInt8Int32,等)。或者,您可以将协议扩展与结构扩展结合使用,以向多个现有类型添加相同的功能—例如,对CGPoint和都添加向量算术支持CGVector

Java和C#在语言级别上实际上没有用户可创建/可扩展的“普通旧数据”类型,因此此处实际上没有类似物。Swift大量使用值类型-
与ObjC,C#和Java不同,在Swift中,甚至集合都是写时复制值类型。这有助于解决有关可变性和线程安全性的许多问题,因此,使自己的值类型而不是始终使用类可以帮助您编写更好的代码。(请参阅WWDC15
中的使用Swift值类型中构建更好的应用程序。)

协议扩展可能受到限制。

例如,您可以具有一个扩展,该扩展CollectionType仅在集合的基础元素类型满足某些条件时才向其中添加方法。这是找到集合最大元素的方法-
在数字或字符串的集合上显示此属性,但是在UIViews(不是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演讲中,有一些受约束的协议扩展的更好的例子(也许还有更多,但我还没有赶上视频):

抽象类(使用包括ObjC或Swift在内的任何语言,它们都是编码约定而不是语言功能)沿着类继承行工作,因此所有子类都继承抽象类功能,无论它是否有意义。

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

这更像是一头挠头,但如果使用得当,它确实可以强大。这是一个基本示例(同样来自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
在Swift中的面向协议的编程中所述,您可以使用它来选择哪些功能应该是可以由采用协议的客户端自定义的替代点,以及哪些功能应该始终是该协议提供的标准功能。

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

As you’ve noted already, protocol conformance is a form of multiple
inheritance. If your type conforms to multiple protocols, and those protocols
have extensions, your type gains the features of all extensions whose
constraints it meets.

You might be aware of other languages that offer multiple inheritance for
classes, where that opens an ugly can of worms because you don’t know what can
happen if you inherit from multiple classes that have the same members or
functions. Swift 2 is a bit better in this regard:

  • Conflicts between protocol extensions are always resolved in favor of the most constrained extension. So, for example, a method on collections of views always wins over the same-named method on arbitrary collections (which in turn wins over the same-named methods on arbitrary sequences, because CollectionType is a subtype of SequenceType).

  • Calling an API that’s otherwise conflicting is a compile error, not a runtime ambiguity.

Protocols (and extensions) can’t create storage.

A protocol definition can require that types adopting the protocol must
implement a property:

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

A type adopting the protocol can choose whether to implement that as a stored
property or a computed property, but either way, the adopting type must
declare its implementation the property.

An extension can implement a computed property, but an extension cannot
add a stored property. This is true whether it’s a protocol extension or an
extension of a specific type (class, struct, or enum).

By contrast, a class can add stored properties to be used by a subclass. And
while there are no language features in Swift to enforce that a superclass
be abstract (that is, you can’t make the compiler forbid instance creation),
you can always create “abstract” superclasses informally if you want to make
use of this ability.

2020-07-07