假设我有两个协议:
protocol TheirPcol {}
protocol MyPcol {
func extraFunc()
}
我想要做的是为'他们的人生成一个协议扩展程序。这使得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()
这方面的标志是'他们的','他们的结构'都由我无法控制的外部API处理。所以我通过了实例'。'
可以这样做吗?或者我将不得不做这样的事情:
struct TheirStruct:TheirPcol {}
let inst = TheirStruct() as! MyPcol
inst.extraFunc()
答案 0 :(得分:10)
似乎有两个用例,说明为什么你可能想做你正在做的事情。在第一个用例中,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
并将其发送到其他函数在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:)
来获取元类型。
您应该查看Conditional conformances,一个被接受加入Swift 4的提案。具体来说,此提案概述了具有以下扩展名的能力:
extension Array: Equatable where Element: Equatable {
static func ==(lhs: Array<Element>, rhs: Array<Element>) -> Bool { ... }
}
虽然这不是你所要求的,但在底部你会发现&#34;替代品被认为&#34;,它有一个名为&#34的子部分;扩展协议以符合协议&# 34;,这是你正在尝试做的更多。它提供了以下示例:
extension Collection: Equatable where Iterator.Element: Equatable {
static func ==(lhs: Self, rhs: Self) -> Bool {
// ...
}
}
然后说明以下内容:
此协议扩展将使任何Equatable元素集合Equatable,这是一个可以很好地使用的强大功能。引入协议扩展的条件一致性会加剧一致性重叠的问题,因为说上述协议扩展的存在意味着没有符合Collection的类型可以声明它自己与Equatable,条件或其他方式的一致性是不合理的。 / p>
虽然我意识到你并没有要求具备条件一致性的能力,但这是关于扩展协议以符合其他协议的讨论的最接近的事情。