当前位置: 首页 > 面试题库 >

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

邢令
2023-03-14
问题内容

可以说我有两个协议:

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。就像编译器错误指出的那样,您不能扩展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,有条件或其他条件的一致性。

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



 类似资料:
  • 问题内容: 自从更新到最新的Xcode 6 DP3以来,我的Swift代码中出现了很多警告和错误。大多数问题已通过采用新更改的语法解决,但是出现了一个似乎很奇怪的错误。 以下代码给出了错误: 有没有人有办法解决吗?我可能在这里忽略了一些简单的事情。 谢谢 问题答案: Beta 3中存在回归,导致无法与if not 或进行比较。 这是由于删除了定义了相等运算符的类型而导致的错误。现在是一个文字。该漏

  • 问题内容: 我想扩展以增加对新协议的一致性-但仅适用于其元素本身符合特定协议的数组。 更笼统地说,我想让带有类型参数的类型(无论是协议类型还是具体类型)仅在类型参数与某些约束匹配时才实现协议。 从Swift 2.0开始,这似乎是不可能的。有什么我想念的方式吗? 例 假设我们有以下协议: 我们可以扩展现有的类型来实现它: 我们还可以扩展实现其所有元素时的实现: 在这一点上,类型本身应该实现,因为它符

  • 据我所知,协议缓冲区主要用于控制服务器和客户端代码的项目。我的一般问题是——协议缓冲区能否用于将二进制消息序列化/反序列化到使用现有协议的服务器?所以,我的问题: > 如果协议缓冲区不支持本机微调现有协议的序列化/反序列化方式,那么可以通过扩展添加该功能吗?是否可以以某种方式添加序列化/反序列化方法可以识别的关键字?也许这可以通过扩展或修改protobuf csharp port或protobuf

  • 在Scapy中添加新的协议(或者是更加的高级:新的协议层)是非常容易的。所有的魔法都在字段中,如果你需要的字段已经有了,你就不必对这个协议太伤脑筋,几分钟就能搞定了。 简单的例子 每一个协议层都是Packet类的子类。协议层背后所有逻辑的操作都是被Packet类和继承的类所处理的。一个简单的协议层是被一系列的字段构成,他们关联在一起组成了协议层,解析时拆分成一个一个的字符串。这些字段都包含在名为f

  • 扩展说明 RPC 协议扩展,封装远程调用细节。 契约: 当用户调用 refer() 所返回的 Invoker 对象的 invoke() 方法时,协议需相应执行同 URL 远端 export() 传入的 Invoker 对象的 invoke() 方法。 其中,refer() 返回的 Invoker 由协议实现,协议通常需要在此 Invoker 中发送远程请求,export() 传入的 Invoker

  • 协议和扩展 你可以扩展一个已经存在的类型来采纳和遵循一个新协议, 就算是你无法访问现有类型的源代码也行. 扩展可以添加新的属性、方法和下标到已经存在的类型, 并且因此允许你添加协议需要的任何需要. protocol TextRepresentable { var textualDescription: String { get } } // 此处并无Dice这个类, 以及其sides属性