首页 > 解决方案 > 是否可以仅显式地遵守协议?

问题描述

第一件事。因为我知道这是不可避免的,所以这里有一个关于同一主题的类似问题。虽然主题相同, 但其推理/用法的意图不同。因此,解决 这个问题与实现我在这里提出的问题不同。因此,请在将其标记为重复之前阅读我要解决的问题。谢谢!

在 Swift 中,我们使用与其他语言中的接口相似(但不完全相同)的协议。我在其他语言(例如 C#)中看到的一件事是隐式和显式实现接口的能力。我想知道 Swift 是否具有后者的能力。

这是使用 Swift 语法显示的概念。请注意,这不会编译。它只是说明性的。

protocol DateSortable{
    var sortDate:Date { get }
}

struct OrderedItem : DateSortable {

    // Implicit conformance because the name sortDate matches the protocol
    let sortDate:Date
}

struct Invoice : DateSortable {

    let invoiceDate:Date

    // Explicit conformance - Note you must specify the protocol name
    // Additionally, you cannot access 'invoice.sortDate' directly
    // You must cast to 'DateSortable' first
    var DateSortable.sortDate:Date { return invoiceDate }
}

let someDate      = orderedItem.sortDate                // Allowed
let someOtherDate = invoice.sortDate                    // *NOT* Allowed
let antherDate    = (invoice as! DateSortable).sortDate // Allowed

同样,上面是伪代码,但说明了其他语言如何支持此功能。

显式一致性的优点和好处

显式一致性的第一个优点是您可以遵循协议而不会弄乱您自己的接口。

例如,如果您有十个协议都定义了一个日期,它在功能上与您模型中的日期匹配,但它们使用十个不同的名称,显式一致性将允许您符合所有十个,而不必公开公开你界面上的那十个不同的名字。(即上面,即使它符合which expects也Invoice只能直接暴露。)invoiceDateDateSortablesortDate

第二个优点是它可以保护您免受成员命名冲突。

考虑两个不相关的协议,例如OrderableDeliverable不幸地为其成员选择了相同的名称,var date:Date{ get }并且它们不属于您。它们位于您正在使用的框架中。

现在在您自己的PurchaseItem模型中,您同时拥有orderDatedeliveryDate。明确的一致性将解决这个问题,就像这样......

extension PurchaseItem : Orderable {
    var Orderable.date:Date { return orderDate }
}

extension PurchaseItem : Deliverable {
    var Deliverable.date:Date { return deliveryDate }
}

简而言之,显式接口声明让您可以按功能关联事物,而不仅仅是盲目地按名称。如果您愿意,您仍然可以按名称关联它们,因为这是自动的,但这不再是必需的。

那么,Swift 有没有和上面类似的东西呢?

关闭,但不完全!

我能想到的最接近的事情是一个私有扩展,在需要它的站点上添加对该协议的一致性,就像这样......

private extension Invoice : DateSortable {
    var DateSortable.sortDate:Date { return invoiceDate }
}

let someDate = invoice.sortDate // Only valid in the scope of this extension

但是,如此处所示,这种方法存在局限性和警告。诚然,该问题的需要是不同的,但注意事项保持不变。

标签: swiftprotocolsexplicit-interface

解决方案


推荐阅读