可以说我有两个协议:
protocol TheirPcol {} protocol MyPcol { func extraFunc() }
我想要做的是为“ TheirPcol”创建一个协议扩展,该协议扩展允许extraFunc()在符合“ TheirPcol”的任何事物上工作。所以像这样:
extraFunc()
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()
似乎有两个用例说明为什么您想做自己正在做的事情。在第一个用例中,Swift允许您做自己想做的事,但在第二个用例中做得不太干净。我猜您属于第二类,但我将同时介绍这两种类型。
TheirPcol
您可能要执行此操作的原因之一仅仅是为赋予了额外的功能TheirPcol。就像编译器错误指出的那样,您不能扩展Swift协议以遵守其他协议。但是,您可以简单地扩展TheirPcol。
extension TheirPcol { func extraFunc() { /* do magic */ } }
在这里,您将提供符合TheirPcol该方法的所有对象,extraFunc()并为其提供默认实现。这样就完成了为符合的对象扩展功能的任务TheirPcol,并且如果您希望它也适用于自己的对象,则可以使您的对象符合TheirPcol。但是,在许多情况下,您希望保留MyPcol为主要协议,而只是将其TheirPcol视为MyPcol。不幸的是,Swift当前不支持协议扩展声明与其他协议的一致性。
MyPcol
在用例(很可能是您的用例)中,您确实确实确实需要单独存在MyPcol,因此据我所知,还没有一种干净的方法来执行所需的操作。以下是一些可行但不理想的解决方案:
一个潜在的杂乱的办法是有一个struct或class像下面这样:
struct
class
struct TheirPcolWrapper<T: TheirPcol>: MyPcol { var object: T func extraFunc() { /* Do magic using object */ } }
从理论上讲,当您需要使现有对象实例符合时,可以将此结构用作强制转换的替代方法MyPcol。或者,如果您具有接受MyPcol为通用参数的函数TheirPcol,则可以创建接受的等效函数,然后将其转换为TheirPcolWrapper并发送给另一个接受in的函数MyPcol。
TheirPcolWrapper
要注意的另一件事是,如果要向您传递的对象TheirPcol,则必须TheirPcolWrapper先将其转换为显式类型,然后才能创建实例。这是由于Swift的一些泛型限制。因此,这样的对象可以作为替代方案:
struct TheirPcolWrapper: MyPcol { var object: MyPcol func extraFunc() { /* Do magic using object */ } }
这意味着您可以在TheirPcolWrapper不知道给出的显式类型的情况下创建实例TheirPcol。
但是,对于一个大型项目,这两者都可能很快变得混乱。
另一个非理想的解决方案是扩展您知道符合TheirPcol并希望支持的每个对象。例如,假设您知道ObjectA并且ObjectB符合TheirPcol。您可以创建的子协议,MyPcol然后显式声明两个对象的一致性,如下所示:
ObjectA
ObjectB
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:)来获取元类型,但这也会成为问题。
type(of:)
您应该检查条件一致性,这是一个包含在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,有条件或其他条件的一致性。
虽然我意识到您并不是在要求具备 条件 一致性的功能,但这是我在讨论将协议扩展为符合其他协议时最能找到的东西。