斯威夫特:是否可以在协议中添加协议扩展?

喝:

可以说我有两个协议:

protocol TheirPcol {}
protocol MyPcol {
    func extraFunc()
}

我想要做的是为“ TheirPcol”创建一个协议扩展,该协议扩展允许extraFunc()在符合“ TheirPcol”的任何事物上工作。所以像这样:

extension TheirPcol : MyPcol { // Error 'Extension of protocol 'TheirPcol' cannot have an inheritance clause.
    func extraFunc() { /* do magic */}
}

struct TheirStruct:TheirPcol {}
let inst = TheirStruct()
inst.extraFunc()

关键是“ TheirPcol”,“ TheirStruct”全部由我无法控制的外部API处理。因此,我通过了实例“ inst”。

能做到吗?还是我必须做这样的事情:

struct TheirStruct:TheirPcol {}
let inst = TheirStruct() as! MyPcol
inst.extraFunc()
马修·希曼(Matthew Seaman):

似乎有两个用例说明为什么您想做自己正在做的事情。在第一个用例中,Swift可以让您做自己想做的事,但在第二个用例中却做得不太干净。我猜您属于第二类,但我会同时介绍这两种。

扩展功能 TheirPcol

您可能要执行此操作的原因之一只是为赋予了额外的功能TheirPcol就像编译器错误指出的那样,您不能扩展Swift协议以遵守其他协议。但是,您可以简单地扩展TheirPcol

extension TheirPcol {
    func extraFunc() { /* do magic */ }
}

在这里,您将提供符合TheirPcol该方法的所有对象,extraFunc()并为其提供默认实现。这样就完成了扩展符合对象功能的任务TheirPcol,如果您也希望将其应用于自己的对象,则可以使对象符合TheirPcol但是,在许多情况下,您希望保留MyPcol为主要协议,而只是将其TheirPcol视为MyPcol不幸的是,Swift当前不支持声明与其他协议一致的协议扩展。

像使用TheirPcol对象一样使用对象MyPcol

在用例(很可能是您的用例)中,您确实确实确实需要单独存在MyPcol,因此据我所知,还没有一种干净的方法来执行所需的操作。以下是一些可行但不理想的解决方案:

包装周围 TheirPcol

一个潜在的杂乱的办法是有一个structclass像下面这样:

struct TheirPcolWrapper<T: TheirPcol>: MyPcol {
    var object: T

    func extraFunc() { /* Do magic using object */ }
}

从理论上讲,当您需要使现有对象实例符合时,可以将此结构用作强制转换的替代方法MyPcol或者,如果您具有接受MyPcol为通用参数的函数TheirPcol,则可以创建接受的等效函数,然后将其转换为TheirPcolWrapper并发送给另一个接受in的函数MyPcol

要注意的另一件事是,如果要向您传递的对象TheirPcol,则必须TheirPcolWrapper先将其转换为显式类型,然后才能创建实例。这是由于Swift的一些泛型限制。因此,这样的对象可以作为替代方案:

struct TheirPcolWrapper: MyPcol {
    var object: MyPcol

    func extraFunc() { /* Do magic using object */ }
}

这意味着您可以在TheirPcolWrapper不知道TheirPcol给定显式类型的情况下创建实例

但是,对于一个大型项目,这两者都可能很快变得混乱。

使用子协议扩展单个对象

另一个非理想的解决方案是扩展您知道符合TheirPcol并希望支持的每个对象例如,假设您知道ObjectA并且ObjectB符合TheirPcol您可以创建的子协议,MyPcol然后显式声明两个对象的一致性,如下所示:

protocol BridgedToMyPcol: TheirPcol, MyPcol {}

extension BridgedToMyPcol {
    func extraFunc() {
        // Do magic here, given that the object is guaranteed to conform to TheirPcol
    }
}

extension ObjectA: BridgedToMyPcol {}
extension ObjectB: BridgedToMyPcol {}

不幸的是,如果您希望支持大量对象,或者如果您无法提前知道对象将是什么,则这种方法就会失败。当您不知道TheirPcol给定的显式类型时,即使您可以使用它type(of:)来获取元类型,这也将成为问题

关于Swift 4的注释

您应该检查条件一致性,这是一个包含在Swift 4中的提议。具体地说,该提议概述了具有以下扩展的功能:

extension Array: Equatable where Element: Equatable {
    static func ==(lhs: Array<Element>, rhs: Array<Element>) -> Bool { ... }
}

尽管这并不是您要问的,但在底部您会找到“考虑到的替代方案”,其中有一个小节,名为“扩展协议以符合协议”,这是您要做的更多工作。它提供以下示例:

extension Collection: Equatable where Iterator.Element: Equatable {
    static func ==(lhs: Self, rhs: Self) -> Bool {
        // ...
    }
}

然后说明以下内容:

此协议扩展将使所有Equatable元素的集合成为Equatable,这是可以充分利用的强大功能。为协议扩展引入条件一致性会加剧重叠一致性的问题,因为说上述协议扩展的存在并不合理,这意味着没有任何符合Collection的类型可以声明其自身对Equatable,有条件或其他条件的一致性。

虽然我意识到您并不是在要求具有条件一致性的功能,但这是我在讨论将协议扩展为符合其他协议时最能找到的东西。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章