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

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

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

回答(1)

3 years ago

有几个重要的区别......

协议扩展可以使用值类型和类 .

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

Java和C#don 't really have user-creatable/extensible 356169 types at a language level, so there'在这里并不是一个类似的东西 . Swift使用了很多值类型 - 与ObjC,C#和Java不同,在Swift中甚至集合都是写时复制值类型 . 这有助于解决许多关于可变性和线程安全性的问题,因此创建自己的值类型而不是始终使用类可以帮助您编写更好的代码 . (参见WWDC15的Building Better Apps with Value Types in Swift . )

协议扩展可以受到约束 .

例如,只有当集合's underlying element type meets some criteria. Here'找到集合的最大元素 - 在数字或字符串的集合上,此属性显示,但是在集合上,例如, UIView s(不是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,它们都是编码约定而不是语言特性 - 沿着类继承行工作,因此所有子类都继承抽象类功能,无论它是否有意义 .

协议可以选择静态或动态分派 .

这个's more of a head-scratcher, but can be really powerful if used well. Here'是一个基本的例子(同样来自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中所述,您可以使用它来选择哪些功能应该是覆盖点,这些功能可以由采用协议的客户端自定义,哪些功能应该始终是协议提供的标准功能 .

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

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

您可能知道为类提供多重继承的其他语言,这会打开一个丑陋的蠕虫,因为您不知道如果从具有相同成员或函数的多个类继承会发生什么 . Swift 2在这方面要好一些:

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

  • 调用其他方面存在冲突的API是编译错误,而不是运行时歧义 .

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

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

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

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

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

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