可以说我有两个协议:
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()
似乎有两个用例说明为什么您想做自己正在做的事情。在第一个用例中,Swift可以让您做自己想做的事,但在第二个用例中却做得不太干净。我猜您属于第二类,但我会同时介绍这两种。
TheirPcol
您可能要执行此操作的原因之一只是为赋予了额外的功能TheirPcol
。就像编译器错误指出的那样,您不能扩展Swift协议以遵守其他协议。但是,您可以简单地扩展TheirPcol
。
extension TheirPcol {
func extraFunc() { /* do magic */ }
}
在这里,您将提供符合TheirPcol
该方法的所有对象,extraFunc()
并为其提供默认实现。这样就完成了扩展符合对象功能的任务TheirPcol
,如果您也希望将其应用于自己的对象,则可以使对象符合TheirPcol
。但是,在许多情况下,您希望保留MyPcol
为主要协议,而只是将其TheirPcol
视为MyPcol
。不幸的是,Swift当前不支持声明与其他协议一致的协议扩展。
TheirPcol
对象一样使用对象MyPcol
在用例(很可能是您的用例)中,您确实确实确实需要单独存在MyPcol
,因此据我所知,还没有一种干净的方法来执行所需的操作。以下是一些可行但不理想的解决方案:
TheirPcol
一个潜在的杂乱的办法是有一个struct
或class
像下面这样:
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中的提议。具体地说,该提议概述了具有以下扩展的功能:
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] 删除。
我来说两句